From dbd40fe7d3219cb69f39627637bbd6d85d88cc59 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 Apr 2026 23:03:51 +0200 Subject: [PATCH 1/8] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 6 +- .../Sources/BrowserInstantPageContent.swift | 418 +++- .../BrowserUI/Sources/BrowserMarkdown.swift | 1143 +++++++++ .../BrowserUI/Sources/BrowserPdfContent.swift | 2 +- .../BrowserUI/Sources/BrowserScreen.swift | 249 +- .../Sources/BrowserToolbarComponent.swift | 53 +- submodules/BrowserUI/Sources/Utils.swift | 2 - .../Sources/Node/ChatListItem.swift | 175 +- .../Sources/Node/ChatListItemStrings.swift | 12 +- .../ReactionListContextMenuContent.swift | 63 +- .../Sources/ResizableSheetComponent.swift | 373 ++- .../ContextUI/Sources/ContextController.swift | 7 + .../Sources/InstantPageContentNode.swift | 24 +- .../Sources/InstantPageControllerNode.swift | 407 +++- .../Sources/InstantPageImageItem.swift | 2 +- .../Sources/InstantPageImageNode.swift | 239 +- .../Sources/InstantPageMedia.swift | 25 + .../Sources/InstantPageNode.swift | 5 + .../Sources/InstantPageSlideshowItem.swift | 3 +- .../InstantPageSlideshowItemNode.swift | 21 +- .../Sources/InstantPageSubContentNode.swift | 20 +- .../Sources/InstantPageTileNode.swift | 13 +- submodules/LocationUI/BUILD | 1 + .../Sources/LocationInfoListItem.swift | 2 +- .../Sources/LocationMapHeaderNode.swift | 30 +- .../Sources/LocationViewController.swift | 77 +- .../Sources/LocationViewControllerNode.swift | 166 +- .../Sources/MediaPickerScreen.swift | 3 - submodules/MimeTypes/Sources/TGMimeTypeMap.m | 1 + .../Sources/SharePeersContainerNode.swift | 15 +- .../Sources/SparseItemGridScrollingArea.swift | 2 +- .../Resources/PresentationResourceKey.swift | 6 + .../PresentationResourcesChatList.swift | 36 + submodules/TelegramUI/BUILD | 2 + .../Components/AdminUserActionsSheet/BUILD | 1 + .../AdminUserActionsPeerComponent.swift | 2 +- .../Sources/AdminUserActionsSheet.swift | 2075 +++++++++-------- .../Sources/ButtonComponent.swift | 74 +- .../ChatMessagePollBubbleContentNode.swift | 809 ++++--- .../ChatMessageTodoBubbleContentNode.swift | 8 +- .../ChatEntityKeyboardInputNode/BUILD | 1 + .../Sources/PaneSearchBarNode.swift | 500 ---- .../Sources/PaneSearchContainerNode.swift | 97 +- .../ChatScheduleTimeController/BUILD | 2 + .../Sources/ChatScheduleTimeScreen.swift | 186 +- .../Sources/ComposeTodoScreen.swift | 6 + .../Sources/ContextActionsContainerNode.swift | 7 + .../Sources/ListActionItemComponent.swift | 19 +- .../ListComposePollOptionComponent.swift | 17 +- .../ListItems/PeerInfoScreenCommentItem.swift | 6 +- .../Sources/PeerInfoSettingsItems.swift | 41 +- .../CallIncomingIcon.imageset/Contents.json | 12 + .../incoming_call_20.pdf | Bin 0 -> 6022 bytes .../CallOutgoingIcon.imageset/Contents.json | 12 + .../outgoing_call_20.pdf | Bin 0 -> 5988 bytes .../Contents.json | 12 + .../incoming_video_call_20.pdf | Bin 0 -> 6040 bytes .../Contents.json | 12 + .../outgoing_video_call_20.pdf | Bin 0 -> 6059 bytes .../Chat List/GameIcon.imageset/Contents.json | 12 + .../GameIcon.imageset/gamepad_20.pdf | Bin 0 -> 6049 bytes .../Chat List/TodoIcon.imageset/Contents.json | 12 + .../TodoIcon.imageset/checklist_20.pdf | Bin 0 -> 5807 bytes .../Animations/NavigationMuteOff.tgs | Bin 0 -> 1246 bytes .../Resources/Animations/NavigationMuteOn.tgs | Bin 0 -> 1237 bytes .../TelegramUI/Sources/AppDelegate.swift | 8 + .../TelegramUI/Sources/ChatController.swift | 2 +- .../Sources/ChatControllerAdminBanUsers.swift | 31 +- .../Sources/ChatControllerNode.swift | 2 +- ...rollerOpenMessageReactionContextMenu.swift | 34 +- .../ChatControllerOpenMessageShareMenu.swift | 53 + .../ChatInterfaceStateContextMenus.swift | 24 + .../TelegramUI/Sources/OpenChatMessage.swift | 9 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 2 +- .../Sources/SharedAccountContext.swift | 4 +- .../Sources/StringWithAppliedEntities.swift | 116 +- 76 files changed, 5186 insertions(+), 2625 deletions(-) create mode 100644 submodules/BrowserUI/Sources/BrowserMarkdown.swift delete mode 100644 submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchBarNode.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/incoming_call_20.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/outgoing_call_20.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallVideoIncomingIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallVideoIncomingIcon.imageset/incoming_video_call_20.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallVideoOutgoingIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/CallVideoOutgoingIcon.imageset/outgoing_video_call_20.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/GameIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/GameIcon.imageset/gamepad_20.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/TodoIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/TodoIcon.imageset/checklist_20.pdf create mode 100644 submodules/TelegramUI/Resources/Animations/NavigationMuteOff.tgs create mode 100644 submodules/TelegramUI/Resources/Animations/NavigationMuteOn.tgs diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index c6e9ae24b3..71e02d506c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -16202,5 +16202,9 @@ Error: %8$@"; "Settings.About.PrivacyHelpEmpty" = "A few words about you."; "Settings.About.PrivacyHelpEveryone" = "Everyone can see your bio. [Change >]()"; -"Settings.About.PrivacyHelpContacts" = "Only uour contacts can see your bio. [Change >]()"; +"Settings.About.PrivacyHelpContacts" = "Only your contacts can see your bio. [Change >]()"; "Settings.About.PrivacyHelpNobody" = "Nobody can see your bio. [Change >]()"; + +"Settings.Birthday.PrivacyHelpEveryone" = "Everyone can see your birthday. [Change >]()"; +"Settings.Birthday.PrivacyHelpContacts" = "Only your contacts can see your birthday. [Change >]()"; +"Settings.Birthday.PrivacyHelpNobody" = "Nobody can see your birthday. [Change >]()"; diff --git a/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift b/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift index ec69d0ec82..4f9c55b877 100644 --- a/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift +++ b/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift @@ -65,6 +65,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg var currentWebEmbedHeights: [Int : CGFloat] = [:] var currentExpandedDetails: [Int : Bool]? var currentDetailsItems: [InstantPageDetailsItem] = [] + private var resolvedExternalMediaDimensions: [MediaId: PixelDimensions] = [:] + private var pendingResolvedExternalMediaDimensions = Set() var currentAccessibilityAreas: [AccessibilityAreaNode] = [] @@ -87,6 +89,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg private let loadWebpageDisposable = MetaDisposable() private let resolveUrlDisposable = MetaDisposable() private let updateLayoutDisposable = MetaDisposable() + private let updateExternalMediaDimensionsDisposable = MetaDisposable() private let loadProgress = ValuePromise(1.0, ignoreRepeated: true) private let readingProgress = ValuePromise(0.0, ignoreRepeated: true) @@ -179,12 +182,14 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg } self.scrollNode.view.addGestureRecognizer(recognizer) - self.webpageDisposable = (actualizedWebpage(account: context.account, webpage: webPage) |> deliverOnMainQueue).start(next: { [weak self] result in - guard let self else { - return - } - self.updateWebPage(result, anchor: self.initialAnchor) - }) + if case let .Loaded(content) = webPage.content, let scheme = URL(string: content.url)?.scheme?.lowercased(), scheme == "http" || scheme == "https" { + self.webpageDisposable = (actualizedWebpage(account: context.account, webpage: webPage) |> deliverOnMainQueue).start(next: { [weak self] result in + guard let self else { + return + } + self.updateWebPage(result, anchor: self.initialAnchor) + }) + } } deinit { @@ -193,6 +198,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg self.loadWebpageDisposable.dispose() self.resolveUrlDisposable.dispose() self.updateLayoutDisposable.dispose() + self.updateExternalMediaDimensionsDisposable.dispose() } required init?(coder: NSCoder) { @@ -304,6 +310,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg } else { self.webPage = nil } + self.resolvedExternalMediaDimensions.removeAll() + self.pendingResolvedExternalMediaDimensions.removeAll() if let anchor = anchor { self.initialAnchor = anchor.removingPercentEncoding } else if let state = state { @@ -478,17 +486,12 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg } private func updatePageLayout() { - guard let (size, insets, _) = self.containerLayout, let (webPage, instantPage) = self.webPage else { + guard let (size, insets, _) = self.containerLayout, let (webPage, instantPage) = self.resolvedWebPage() else { return } let currentLayout = instantPageLayoutForWebPage(webPage, instantPage: instantPage, userLocation: self.sourceLocation.userLocation, boundingWidth: size.width, safeInset: insets.left, strings: self.presentationData.strings, theme: self.theme, dateTimeFormat: self.presentationData.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights) - for (_, tileNode) in self.visibleTiles { - tileNode.removeFromSupernode() - } - self.visibleTiles.removeAll() - let currentLayoutTiles = instantPageTilesFromLayout(currentLayout, boundingWidth: size.width) var currentDetailsItems: [InstantPageDetailsItem] = [] @@ -655,6 +658,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg topNode = newNode self.visibleItemsWithNodes[itemIndex] = newNode itemNode = newNode + self.configureExternalMediaDimensionsUpdates(for: newNode) if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.requestLayoutUpdate = { [weak self] animated in @@ -678,6 +682,10 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg } } + if let itemNode = itemNode { + self.configureExternalMediaDimensionsUpdates(for: itemNode) + } + if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.updateVisibleItems(visibleBounds: visibleBounds.offsetBy(dx: -itemNode.frame.minX, dy: -itemNode.frame.minY), animated: animated) } @@ -708,8 +716,11 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg topNode = tileNode self.visibleTiles[tileIndex] = tileNode } else { - if visibleTiles[tileIndex]!.frame != tileFrame { - transition.updateFrame(node: self.visibleTiles[tileIndex]!, frame: tileFrame) + if let tileNode = self.visibleTiles[tileIndex] { + tileNode.update(tile: tile, backgroundColor: theme.pageBackgroundColor) + if tileNode.frame != tileFrame { + transition.updateFrame(node: tileNode, frame: tileFrame) + } } } } @@ -929,6 +940,385 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg return nil } + private func configureExternalMediaDimensionsUpdates(for itemNode: InstantPageNode) { + let update: (MediaId, PixelDimensions) -> Void = { [weak self] mediaId, dimensions in + self?.updateExternalMediaDimensions(mediaId, dimensions) + } + if let itemNode = itemNode as? InstantPageExternalMediaDimensionsNode { + itemNode.updateExternalMediaDimensions = update + } + if let itemNode = itemNode as? InstantPageDetailsNode { + itemNode.contentNode.updateExternalMediaDimensions = update + } + } + + private func updateExternalMediaDimensions(_ mediaId: MediaId, _ dimensions: PixelDimensions) { + if self.resolvedExternalMediaDimensions[mediaId] == dimensions { + return + } + self.resolvedExternalMediaDimensions[mediaId] = dimensions + self.pendingResolvedExternalMediaDimensions.insert(mediaId) + + let signal: Signal = (.complete() |> delay(0.08, queue: Queue.mainQueue())) + self.updateExternalMediaDimensionsDisposable.set(signal.start(completed: { [weak self] in + self?.relayoutForResolvedExternalMediaDimensions() + })) + } + + private func relayoutForResolvedExternalMediaDimensions() { + guard !self.pendingResolvedExternalMediaDimensions.isEmpty else { + return + } + + let mediaIds = Array(self.pendingResolvedExternalMediaDimensions) + self.pendingResolvedExternalMediaDimensions.removeAll() + + let detailsStateMaps = self.captureExpandedDetailsStateMaps() + let viewportTop = self.scrollNode.view.contentOffset.y + self.scrollNode.view.contentInset.top + var oldFrames: [MediaId: CGRect] = [:] + for mediaId in mediaIds { + if let frame = self.effectiveFrameForMedia(mediaId, detailsStateMaps: detailsStateMaps) { + oldFrames[mediaId] = frame + } + } + + self.updatePageLayout() + + var newFrames: [MediaId: CGRect] = [:] + for mediaId in mediaIds { + if let frame = self.effectiveFrameForMedia(mediaId, detailsStateMaps: detailsStateMaps) { + newFrames[mediaId] = frame + } + } + + if let compensatedViewportTop = self.compensatedViewportTop(oldFrames: oldFrames, newFrames: newFrames, viewportTop: viewportTop) { + self.setViewportTop(compensatedViewportTop) + } + self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds) + } + + private func setViewportTop(_ viewportTop: CGFloat) { + let scrollView = self.scrollNode.view + let minOffsetY = -scrollView.contentInset.top + let maxOffsetY = max(minOffsetY, scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom) + let contentOffsetY = min(max(viewportTop - scrollView.contentInset.top, minOffsetY), maxOffsetY) + if contentOffsetY.isFinite { + scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: contentOffsetY) + } + } + + private func compensatedViewportTop(oldFrames: [MediaId: CGRect], newFrames: [MediaId: CGRect], viewportTop: CGFloat) -> CGFloat? { + var pairedFrames: [(old: CGRect, new: CGRect)] = [] + for (mediaId, oldFrame) in oldFrames { + if let newFrame = newFrames[mediaId] { + pairedFrames.append((oldFrame, newFrame)) + } + } + if pairedFrames.isEmpty { + return nil + } + + if let intersecting = pairedFrames + .filter({ $0.old.height > 0.0 && $0.new.height > 0.0 && viewportTop > $0.old.minY && viewportTop < $0.old.maxY }) + .max(by: { $0.old.minY < $1.old.minY }) { + let ratio = min(max((viewportTop - intersecting.old.minY) / intersecting.old.height, 0.0), 1.0) + return intersecting.new.minY + ratio * intersecting.new.height + } + + if let above = pairedFrames + .filter({ viewportTop >= $0.old.maxY }) + .max(by: { $0.old.maxY < $1.old.maxY }) { + return viewportTop + (above.new.maxY - above.old.maxY) + } + + return nil + } + + private func captureExpandedDetailsStateMaps() -> [String: [Int: Bool]] { + guard let currentLayout = self.currentLayout else { + return [:] + } + var result: [String: [Int: Bool]] = [:] + self.captureExpandedDetailsStateMaps(items: currentLayout.items, visibleItemsWithNodes: self.visibleItemsWithNodes, path: [], result: &result) + return result + } + + private func captureExpandedDetailsStateMaps(items: [InstantPageItem], visibleItemsWithNodes: [Int: InstantPageNode], path: [Int], result: inout [String: [Int: Bool]]) { + let detailsNodes = visibleItemsWithNodes.compactMap { $0.value as? InstantPageDetailsNode } + + var detailsIndex = -1 + for item in items { + guard let detailsItem = item as? InstantPageDetailsItem else { + continue + } + detailsIndex += 1 + + guard let detailsNode = detailsNodes.first(where: { $0.item === detailsItem }) else { + continue + } + let nextPath = path + [detailsIndex] + result[self.detailsStateKey(nextPath)] = detailsNode.contentNode.currentExpandedDetails ?? [:] + self.captureExpandedDetailsStateMaps(items: detailsItem.items, visibleItemsWithNodes: detailsNode.contentNode.visibleItemsWithNodes, path: nextPath, result: &result) + } + } + + private func detailsStateKey(_ path: [Int]) -> String { + if path.isEmpty { + return "" + } + return path.map(String.init).joined(separator: ".") + } + + private func effectiveFrameForMedia(_ mediaId: MediaId, detailsStateMaps: [String: [Int: Bool]]) -> CGRect? { + guard let currentLayout = self.currentLayout else { + return nil + } + return self.effectiveFrameForMedia(mediaId, items: currentLayout.items, origin: .zero, expandedDetails: self.currentExpandedDetails, path: [], detailsStateMaps: detailsStateMaps) + } + + private func effectiveFrameForMedia(_ mediaId: MediaId, items: [InstantPageItem], origin: CGPoint, expandedDetails: [Int: Bool]?, path: [Int], detailsStateMaps: [String: [Int: Bool]]) -> CGRect? { + var collapseOffset: CGFloat = 0.0 + var detailsIndex = -1 + + for item in items { + if item is InstantPageDetailsItem { + detailsIndex += 1 + } + + var itemFrame = item.frame.offsetBy(dx: origin.x, dy: origin.y - collapseOffset) + if let detailsItem = item as? InstantPageDetailsItem { + let nextPath = path + [detailsIndex] + let nestedExpandedDetails = detailsStateMaps[self.detailsStateKey(nextPath)] + let expanded = expandedDetails?[detailsIndex] ?? detailsItem.initiallyExpanded + let height = expanded ? detailsItem.titleHeight + self.effectiveContentHeight(items: detailsItem.items, baseHeight: detailsItem.frame.height - detailsItem.titleHeight, expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) : detailsItem.titleHeight + collapseOffset += item.frame.height - height + itemFrame.size.height = height + + if expanded, let nestedFrame = self.effectiveFrameForMedia(mediaId, items: detailsItem.items, origin: CGPoint(x: itemFrame.minX, y: itemFrame.minY + detailsItem.titleHeight), expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) { + return nestedFrame + } + continue + } + + if self.itemContainsMedia(item, mediaId: mediaId) { + return itemFrame + } + } + + return nil + } + + private func effectiveContentHeight(items: [InstantPageItem], baseHeight: CGFloat, expandedDetails: [Int: Bool]?, path: [Int], detailsStateMaps: [String: [Int: Bool]]) -> CGFloat { + var contentHeight = baseHeight + var detailsIndex = -1 + + for item in items { + guard let detailsItem = item as? InstantPageDetailsItem else { + continue + } + detailsIndex += 1 + + let nextPath = path + [detailsIndex] + let nestedExpandedDetails = detailsStateMaps[self.detailsStateKey(nextPath)] + let expanded = expandedDetails?[detailsIndex] ?? detailsItem.initiallyExpanded + let height = expanded ? detailsItem.titleHeight + self.effectiveContentHeight(items: detailsItem.items, baseHeight: detailsItem.frame.height - detailsItem.titleHeight, expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) : detailsItem.titleHeight + contentHeight += -detailsItem.frame.height + height + } + + return contentHeight + } + + private func itemContainsMedia(_ item: InstantPageItem, mediaId: MediaId) -> Bool { + for media in item.medias { + if media.media.id == mediaId { + return true + } + } + return false + } + + private func resolvedWebPage() -> (webPage: TelegramMediaWebpage, instantPage: InstantPage?)? { + guard let (webPage, instantPage) = self.webPage else { + return nil + } + guard !self.resolvedExternalMediaDimensions.isEmpty, case let .Loaded(content) = webPage.content else { + return (webPage, instantPage) + } + + var instantPageUpdated = false + var effectiveInstantPage = instantPage + if let instantPage { + var media = instantPage.media + for (mediaId, currentMedia) in instantPage.media { + if let updatedMedia = self.updatedMediaIfNeeded(currentMedia) { + media[mediaId] = updatedMedia + instantPageUpdated = true + } + } + if instantPageUpdated { + effectiveInstantPage = InstantPage(blocks: instantPage.blocks, media: media, isComplete: instantPage.isComplete, rtl: instantPage.rtl, url: instantPage.url, views: instantPage.views) + } + } + + var imageUpdated = false + let effectiveImage = content.image.map { image -> TelegramMediaImage in + if let updated = self.updatedImageIfNeeded(image) { + imageUpdated = true + return updated + } else { + return image + } + } + + var fileUpdated = false + let effectiveFile = content.file.map { file -> TelegramMediaFile in + if let updated = self.updatedFileIfNeeded(file) { + fileUpdated = true + return updated + } else { + return file + } + } + + if !instantPageUpdated && !imageUpdated && !fileUpdated { + return (webPage, instantPage) + } + + let effectiveContent = TelegramMediaWebpageLoadedContent( + url: content.url, + displayUrl: content.displayUrl, + hash: content.hash, + type: content.type, + websiteName: content.websiteName, + title: content.title, + text: content.text, + embedUrl: content.embedUrl, + embedType: content.embedType, + embedSize: content.embedSize, + duration: content.duration, + author: content.author, + isMediaLargeByDefault: content.isMediaLargeByDefault, + imageIsVideoCover: content.imageIsVideoCover, + image: effectiveImage, + file: effectiveFile, + story: content.story, + attributes: content.attributes, + instantPage: effectiveInstantPage + ) + return (TelegramMediaWebpage(webpageId: webPage.webpageId, content: .Loaded(effectiveContent)), effectiveInstantPage) + } + + private func updatedMediaIfNeeded(_ media: Media) -> Media? { + if let image = media as? TelegramMediaImage { + return self.updatedImageIfNeeded(image) + } else if let file = media as? TelegramMediaFile { + return self.updatedFileIfNeeded(file) + } else { + return nil + } + } + + private func updatedImageIfNeeded(_ image: TelegramMediaImage) -> TelegramMediaImage? { + guard let dimensions = self.resolvedExternalMediaDimensions[image.imageId] else { + return nil + } + + var updatedRepresentations = image.representations + var didUpdate = false + for i in 0 ..< updatedRepresentations.count { + let representation = updatedRepresentations[i] + guard representation.resource is InstantPageExternalMediaResource, representation.dimensions != dimensions else { + continue + } + updatedRepresentations[i] = TelegramMediaImageRepresentation( + dimensions: dimensions, + resource: representation.resource, + progressiveSizes: representation.progressiveSizes, + immediateThumbnailData: representation.immediateThumbnailData, + hasVideo: representation.hasVideo, + isPersonal: representation.isPersonal, + typeHint: representation.typeHint + ) + didUpdate = true + } + + guard didUpdate else { + return nil + } + return TelegramMediaImage( + imageId: image.imageId, + representations: updatedRepresentations, + videoRepresentations: image.videoRepresentations, + immediateThumbnailData: image.immediateThumbnailData, + emojiMarkup: image.emojiMarkup, + reference: image.reference, + partialReference: image.partialReference, + flags: image.flags, + video: image.video + ) + } + + private func updatedFileIfNeeded(_ file: TelegramMediaFile) -> TelegramMediaFile? { + guard let dimensions = self.resolvedExternalMediaDimensions[file.fileId], file.resource is InstantPageExternalMediaResource else { + return nil + } + + let (attributes, didUpdate) = self.fileAttributesWithResolvedDimensions(file.attributes, dimensions: dimensions) + guard didUpdate else { + return nil + } + + return TelegramMediaFile( + fileId: file.fileId, + partialReference: file.partialReference, + resource: file.resource, + previewRepresentations: file.previewRepresentations, + videoThumbnails: file.videoThumbnails, + videoCover: file.videoCover, + immediateThumbnailData: file.immediateThumbnailData, + mimeType: file.mimeType, + size: file.size, + attributes: attributes, + alternativeRepresentations: file.alternativeRepresentations + ) + } + + private func fileAttributesWithResolvedDimensions(_ attributes: [TelegramMediaFileAttribute], dimensions: PixelDimensions) -> ([TelegramMediaFileAttribute], Bool) { + var updatedAttributes: [TelegramMediaFileAttribute] = [] + var didUpdate = false + var hasSizeAttribute = false + + for attribute in attributes { + switch attribute { + case let .ImageSize(size): + hasSizeAttribute = true + if size != dimensions { + updatedAttributes.append(.ImageSize(size: dimensions)) + didUpdate = true + } else { + updatedAttributes.append(attribute) + } + case let .Video(duration, size, flags, preloadSize, coverTime, videoCodec): + hasSizeAttribute = true + if size != dimensions { + updatedAttributes.append(.Video(duration: duration, size: dimensions, flags: flags, preloadSize: preloadSize, coverTime: coverTime, videoCodec: videoCodec)) + didUpdate = true + } else { + updatedAttributes.append(attribute) + } + default: + updatedAttributes.append(attribute) + } + } + + if !hasSizeAttribute { + updatedAttributes.append(.ImageSize(size: dimensions)) + didUpdate = true + } + + return (updatedAttributes, didUpdate) + } + private func openUrl(_ url: InstantPageUrlItem) { var baseUrl = url.url var anchor: String? diff --git a/submodules/BrowserUI/Sources/BrowserMarkdown.swift b/submodules/BrowserUI/Sources/BrowserMarkdown.swift new file mode 100644 index 0000000000..3f09ec5cd4 --- /dev/null +++ b/submodules/BrowserUI/Sources/BrowserMarkdown.swift @@ -0,0 +1,1143 @@ +import Foundation +import UIKit +import Postbox +import TelegramCore +import AccountContext +import InstantPageUI + +private let markdownPresentationIntentAttribute = NSAttributedString.Key("NSPresentationIntent") +private let markdownInlinePresentationIntentAttribute = NSAttributedString.Key("NSInlinePresentationIntent") +private let markdownLinkAttribute = NSAttributedString.Key("NSLink") +private let markdownImageURLAttribute = NSAttributedString.Key("NSImageURL") +private let markdownAlternateDescriptionAttribute = NSAttributedString.Key("NSAlternateDescription") + +@available(iOS 15.0, *) +private let markdownSoftBreakInlineIntent = InlinePresentationIntent(rawValue: 1 << 6) +@available(iOS 15.0, *) +private let markdownHardBreakInlineIntent = InlinePresentationIntent(rawValue: 1 << 7) +@available(iOS 15.0, *) +private let markdownInlineHTMLInlineIntent = InlinePresentationIntent(rawValue: 1 << 8) + +private let markdownDefaultBlockImageDimensions = PixelDimensions(width: 1200, height: 900) +private let markdownDefaultInlineImageDimensions = PixelDimensions(width: 18, height: 18) + +private struct MarkdownPageResult { + let blocks: [InstantPageBlock] + let media: [MediaId: Media] +} + +private enum MarkdownInlineFragment { + case richText(RichText) + case image(MarkdownResolvedImage) +} + +private struct MarkdownInlineContent { + let fragments: [MarkdownInlineFragment] + + var richText: RichText { + var result: [RichText] = [] + result.reserveCapacity(self.fragments.count) + + for fragment in self.fragments { + switch fragment { + case let .richText(text): + result.append(text) + case let .image(image): + var text: RichText = .image(id: image.mediaId, dimensions: image.inlineDimensions) + if let linkUrl = image.linkUrl { + text = .url(text: text, url: linkUrl, webpageId: nil) + } + result.append(text) + } + } + + return markdownCompact(result) + } + + var standaloneImage: MarkdownResolvedImage? { + var result: MarkdownResolvedImage? + + for fragment in self.fragments { + switch fragment { + case let .richText(text): + if !markdownIsWhitespaceOnly(text) { + return nil + } + case let .image(image): + if result != nil { + return nil + } + result = image + } + } + + return result + } +} + +private struct MarkdownResolvedImage { + let mediaId: MediaId + let inlineDimensions: PixelDimensions + let caption: InstantPageCaption + let linkUrl: String? +} + +private enum MarkdownResolvedImageSource { + case remote(String) + case data(Data, PixelDimensions) + case unsupported +} + +private final class MarkdownConversionContext { + private let context: AccountContext + fileprivate let documentURL: URL + private var nextRemoteMediaId: Int64 = 0 + private var nextLocalMediaId: Int64 = 0 + + private(set) var media: [MediaId: Media] = [:] + + init(context: AccountContext, documentURL: URL) { + self.context = context + self.documentURL = documentURL + } + + func makePageResult(blocks: [InstantPageBlock]) -> MarkdownPageResult { + return MarkdownPageResult(blocks: blocks, media: self.media) + } + + func resolveImage(attributes: [NSAttributedString.Key: Any]) -> MarkdownResolvedImage? { + guard let imageUrl = markdownImageURL(attributes: attributes) else { + return nil + } + + let inlineDimensions = markdownInlineImageDimensions(attributes: attributes) + let caption = markdownImageCaption(markdownAlternateDescription(attributes: attributes)) + let linkUrl = markdownLink(attributes: attributes, documentURL: self.documentURL) + + switch markdownResolveImageSource(imageUrl) { + case let .remote(url): + let mediaId = self.nextMediaId(namespace: Namespaces.Media.CloudImage) + self.media[mediaId] = TelegramMediaImage( + imageId: mediaId, + representations: [ + TelegramMediaImageRepresentation( + dimensions: markdownDefaultBlockImageDimensions, + resource: InstantPageExternalMediaResource(url: url), + progressiveSizes: [], + immediateThumbnailData: nil + ) + ], + immediateThumbnailData: nil, + reference: nil, + partialReference: nil, + flags: [] + ) + return MarkdownResolvedImage( + mediaId: mediaId, + inlineDimensions: inlineDimensions, + caption: caption, + linkUrl: linkUrl + ) + case let .data(data, dimensions): + let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max), size: Int64(data.count), isSecretRelated: false) + self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) + + let mediaId = self.nextMediaId(namespace: Namespaces.Media.LocalImage) + self.media[mediaId] = TelegramMediaImage( + imageId: mediaId, + representations: [ + TelegramMediaImageRepresentation( + dimensions: dimensions, + resource: resource, + progressiveSizes: [], + immediateThumbnailData: nil + ) + ], + immediateThumbnailData: nil, + reference: nil, + partialReference: nil, + flags: [] + ) + return MarkdownResolvedImage( + mediaId: mediaId, + inlineDimensions: inlineDimensions, + caption: caption, + linkUrl: linkUrl + ) + case .unsupported: + return nil + } + } + + private func nextMediaId(namespace: Int32) -> MediaId { + switch namespace { + case Namespaces.Media.LocalImage: + self.nextLocalMediaId += 1 + return MediaId(namespace: namespace, id: self.nextLocalMediaId) + default: + self.nextRemoteMediaId += 1 + return MediaId(namespace: namespace, id: self.nextRemoteMediaId) + } + } +} + +func markdownWebpage(context: AccountContext, file: FileMediaReference) -> (webPage: TelegramMediaWebpage, fileURL: URL)? { + guard #available(iOS 15.0, *) else { + return nil + } + guard let path = context.account.postbox.mediaBox.completedResourcePath(file.media.resource) else { + return nil + } + let fileURL = URL(fileURLWithPath: path) + guard let data = try? Data(contentsOf: fileURL) else { + return nil + } + guard let webPage = markdownWebpage(context: context, file: file, fileURL: fileURL, data: data) else { + return nil + } + return (webPage, fileURL) +} + +@available(iOS 15.0, *) +private func markdownWebpage(context: AccountContext, file: FileMediaReference, fileURL: URL, data: Data) -> TelegramMediaWebpage? { + let attributedString: NSAttributedString + do { + attributedString = try NSAttributedString( + markdown: data, + options: .init(), + baseURL: fileURL.deletingLastPathComponent() + ) + } catch { + return nil + } + + let conversionContext = MarkdownConversionContext(context: context, documentURL: fileURL) + let pageResult = markdownPageResult(from: attributedString, context: conversionContext) + let blocks = markdownBlocksWithGeneratedAnchors(pageResult.blocks) + guard !blocks.isEmpty else { + return nil + } + + let title = markdownTitle(from: blocks, file: file, fileURL: fileURL) + let text = markdownFirstParagraphText(from: blocks) + let instantPage = InstantPage( + blocks: blocks, + media: pageResult.media, + isComplete: true, + rtl: false, + url: fileURL.absoluteString, + views: nil + ) + + return TelegramMediaWebpage( + webpageId: MediaId(namespace: 0, id: 0), + content: .Loaded( + TelegramMediaWebpageLoadedContent( + url: fileURL.absoluteString, + displayUrl: fileURL.absoluteString, + hash: 0, + type: "article", + websiteName: nil, + title: title, + text: text, + embedUrl: nil, + embedType: nil, + embedSize: nil, + duration: nil, + author: nil, + isMediaLargeByDefault: nil, + imageIsVideoCover: false, + image: nil, + file: nil, + story: nil, + attributes: [], + instantPage: instantPage + ) + ) + ) +} + +@available(iOS 15.0, *) +private func markdownPageResult(from attributedString: NSAttributedString, context: MarkdownConversionContext) -> MarkdownPageResult { + var nodesByIdentity: [Int: MarkdownIntentNode] = [:] + var rootNodes: [MarkdownIntentNode] = [] + var rootIdentities: Set = [] + + attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { attributes, range, _ in + guard range.length > 0 else { + return + } + guard let presentationIntent = attributes[markdownPresentationIntentAttribute] as? PresentationIntent else { + return + } + let components = presentationIntent.components + guard !components.isEmpty else { + return + } + + var orderedNodes: [MarkdownIntentNode] = [] + for component in components.reversed() { + let node: MarkdownIntentNode + if let current = nodesByIdentity[component.identity] { + node = current + } else { + let created = MarkdownIntentNode(component: component) + nodesByIdentity[component.identity] = created + node = created + } + orderedNodes.append(node) + } + + if let rootNode = orderedNodes.first, rootIdentities.insert(rootNode.identity).inserted { + rootNodes.append(rootNode) + } + if orderedNodes.count >= 2 { + for index in 0 ..< (orderedNodes.count - 1) { + orderedNodes[index].append(child: orderedNodes[index + 1]) + } + } + if let leafNode = orderedNodes.last { + leafNode.append(text: attributedString.attributedSubstring(from: range)) + } + } + + return context.makePageResult(blocks: markdownBlocks(from: rootNodes, context: context)) +} + +private func markdownBlocks(from nodes: [MarkdownIntentNode], context: MarkdownConversionContext) -> [InstantPageBlock] { + var result: [InstantPageBlock] = [] + for node in nodes { + result.append(contentsOf: markdownBlocks(from: node, context: context)) + } + return result +} + +private func markdownBlocks(from node: MarkdownIntentNode, context: MarkdownConversionContext) -> [InstantPageBlock] { + switch node.kind { + case let .table(alignments): + let rows = markdownTableRows(from: node.children, alignments: alignments, context: context) + guard !rows.isEmpty else { + return [] + } + return [.table(title: .empty, rows: rows, bordered: true, striped: false)] + case let .header(level): + let text = markdownRichText(from: node.attributedText, context: context) + guard markdownHasDisplayableContent(text) else { + return [] + } + if level <= 1 { + return [.title(text)] + } else if level == 2 { + return [.header(text)] + } else { + return [.subheader(text)] + } + case .paragraph: + let inlineContent = markdownInlineContent(from: node.attributedText, context: context) + if let image = inlineContent.standaloneImage { + return [ + .image( + id: image.mediaId, + caption: image.caption, + url: image.linkUrl, + webpageId: nil + ) + ] + } + let text = inlineContent.richText + guard markdownHasDisplayableContent(text) else { + return [] + } + return [.paragraph(text)] + case .codeBlock: + let text = markdownRichText(from: markdownTrimTrailingCodeBlockNewline(node.attributedText), context: context) + guard markdownHasDisplayableContent(text) else { + return [] + } + return [.preformatted(text)] + case .thematicBreak: + return [.divider] + case .blockQuote: + var result: [InstantPageBlock] = [] + for child in node.children { + for childBlock in markdownBlocks(from: child, context: context) { + switch childBlock { + case let .paragraph(text): + result.append(.blockQuote(text: text, caption: .empty)) + default: + let plainText = markdownPlainText(from: childBlock) + if !plainText.isEmpty { + result.append(.blockQuote(text: .plain(plainText), caption: .empty)) + } + } + } + } + return result + case .orderedList: + let items = markdownListItems(from: node.children, ordered: true, context: context) + guard !items.isEmpty else { + return [] + } + return [.list(items: items, ordered: true)] + case .unorderedList: + let items = markdownListItems(from: node.children, ordered: false, context: context) + guard !items.isEmpty else { + return [] + } + return [.list(items: items, ordered: false)] + case .listItem(_), .tableHeaderRow, .tableRow, .tableCell(_), .unknown: + return markdownBlocks(from: node.children, context: context) + } +} + +private func markdownListItems(from nodes: [MarkdownIntentNode], ordered: Bool, context: MarkdownConversionContext) -> [InstantPageListItem] { + var result: [InstantPageListItem] = [] + for node in nodes { + guard case let .listItem(ordinal) = node.kind else { + continue + } + let blocks = markdownBlocks(from: node.children, context: context) + guard !blocks.isEmpty else { + continue + } + let number: String? + if ordered { + number = "\(ordinal)" + } else { + number = nil + } + if blocks.count == 1, case let .paragraph(text) = blocks[0] { + result.append(.text(text, number)) + } else { + result.append(.blocks(blocks, number)) + } + } + return result +} + +private func markdownTableRows(from nodes: [MarkdownIntentNode], alignments: [TableHorizontalAlignment], context: MarkdownConversionContext) -> [InstantPageTableRow] { + var result: [InstantPageTableRow] = [] + for node in nodes { + switch node.kind { + case .tableHeaderRow: + let cells = markdownTableCells(from: node.children, alignments: alignments, header: true, context: context) + if !cells.isEmpty { + result.append(InstantPageTableRow(cells: cells)) + } + case .tableRow: + let cells = markdownTableCells(from: node.children, alignments: alignments, header: false, context: context) + if !cells.isEmpty { + result.append(InstantPageTableRow(cells: cells)) + } + default: + continue + } + } + return result +} + +private func markdownTableCells(from nodes: [MarkdownIntentNode], alignments: [TableHorizontalAlignment], header: Bool, context: MarkdownConversionContext) -> [InstantPageTableCell] { + let maxColumnIndex = nodes.reduce(-1) { partialResult, node in + if case let .tableCell(column) = node.kind { + return max(partialResult, column) + } else { + return partialResult + } + } + let columnCount = max(alignments.count, maxColumnIndex + 1) + guard columnCount > 0 else { + return [] + } + + var result: [InstantPageTableCell] = [] + var nextColumn = 0 + + for node in nodes { + guard case let .tableCell(column) = node.kind else { + continue + } + + while nextColumn < column { + result.append(markdownEmptyTableCell(header: header, alignment: markdownTableAlignment(at: nextColumn, from: alignments))) + nextColumn += 1 + } + + let text = markdownRichText(from: node.attributedText, context: context) + result.append( + InstantPageTableCell( + text: text, + header: header, + alignment: markdownTableAlignment(at: column, from: alignments), + verticalAlignment: .top, + colspan: 1, + rowspan: 1 + ) + ) + nextColumn = max(nextColumn, column + 1) + } + + while nextColumn < columnCount { + result.append(markdownEmptyTableCell(header: header, alignment: markdownTableAlignment(at: nextColumn, from: alignments))) + nextColumn += 1 + } + + return result +} + +private func markdownEmptyTableCell(header: Bool, alignment: TableHorizontalAlignment) -> InstantPageTableCell { + return InstantPageTableCell( + text: .empty, + header: header, + alignment: alignment, + verticalAlignment: .top, + colspan: 1, + rowspan: 1 + ) +} + +private func markdownTableAlignment(at index: Int, from alignments: [TableHorizontalAlignment]) -> TableHorizontalAlignment { + guard index >= 0, index < alignments.count else { + return .left + } + return alignments[index] +} + +private func markdownRichText(from attributedString: NSAttributedString, context: MarkdownConversionContext) -> RichText { + return markdownInlineContent(from: attributedString, context: context).richText +} + +private func markdownInlineContent(from attributedString: NSAttributedString, context: MarkdownConversionContext) -> MarkdownInlineContent { + guard attributedString.length > 0, #available(iOS 15.0, *) else { + return MarkdownInlineContent(fragments: []) + } + + var fragments: [MarkdownInlineFragment] = [] + var htmlStyles: [MarkdownHTMLInlineStyle] = [] + var consumeNextSoftBreak = false + + attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { attributes, range, _ in + guard range.length > 0 else { + return + } + + let text = attributedString.attributedSubstring(from: range).string + guard !text.isEmpty else { + return + } + + let inlineIntent: InlinePresentationIntent? + if let inlineIntentValue = attributes[markdownInlinePresentationIntentAttribute] as? InlinePresentationIntent { + inlineIntent = inlineIntentValue + } else if let inlineIntentValue = attributes[markdownInlinePresentationIntentAttribute] as? NSNumber { + inlineIntent = InlinePresentationIntent(rawValue: inlineIntentValue.uintValue) + } else { + inlineIntent = nil + } + + if let inlineIntent, inlineIntent.contains(markdownInlineHTMLInlineIntent), let directive = markdownHTMLDirective(for: text) { + switch directive { + case let .open(style): + htmlStyles.append(style) + case let .close(style): + if let index = htmlStyles.lastIndex(of: style) { + htmlStyles.remove(at: index) + } + case .lineBreak: + fragments.append(.richText(markdownApplyHTMLStyles(htmlStyles, to: .plain("\n")))) + consumeNextSoftBreak = true + } + return + } + + if consumeNextSoftBreak { + if let inlineIntent, inlineIntent.contains(markdownSoftBreakInlineIntent), text == " " { + consumeNextSoftBreak = false + return + } + consumeNextSoftBreak = false + } + + if let image = context.resolveImage(attributes: attributes) { + fragments.append(.image(image)) + return + } + + var fragment: RichText = .plain(text) + if let inlineIntent { + if inlineIntent.contains(.stronglyEmphasized) { + fragment = .bold(fragment) + } + if inlineIntent.contains(.emphasized) { + fragment = .italic(fragment) + } + if inlineIntent.contains(.strikethrough) { + fragment = .strikethrough(fragment) + } + if inlineIntent.contains(.code) { + fragment = .fixed(fragment) + } + if inlineIntent.contains(markdownHardBreakInlineIntent) { + fragment = .plain("\n") + } + } + + if let url = markdownLink(attributes: attributes, documentURL: context.documentURL) { + fragment = .url(text: fragment, url: url, webpageId: nil) + } + + fragments.append(.richText(markdownApplyHTMLStyles(htmlStyles, to: fragment))) + } + + return MarkdownInlineContent(fragments: fragments) +} + +private enum MarkdownHTMLInlineStyle: Equatable { + case `subscript` + case superscript + case marked +} + +private enum MarkdownHTMLDirective { + case open(MarkdownHTMLInlineStyle) + case close(MarkdownHTMLInlineStyle) + case lineBreak +} + +private func markdownHTMLDirective(for text: String) -> MarkdownHTMLDirective? { + switch text.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() { + case "": + return .open(.subscript) + case "": + return .close(.subscript) + case "": + return .open(.superscript) + case "": + return .close(.superscript) + case "": + return .open(.marked) + case "": + return .close(.marked) + case "
", "
", "
": + return .lineBreak + default: + return nil + } +} + +private func markdownApplyHTMLStyles(_ styles: [MarkdownHTMLInlineStyle], to text: RichText) -> RichText { + var result = text + for style in styles { + switch style { + case .subscript: + result = .subscript(result) + case .superscript: + result = .superscript(result) + case .marked: + result = .marked(result) + } + } + return result +} + +private func markdownAlternateDescription(attributes: [NSAttributedString.Key: Any]) -> String? { + if let value = attributes[markdownAlternateDescriptionAttribute] as? String, !value.isEmpty { + return value + } + return nil +} + +private func markdownImageURL(attributes: [NSAttributedString.Key: Any]) -> String? { + if let value = attributes[markdownImageURLAttribute] as? URL { + return value.absoluteString + } + if let value = attributes[markdownImageURLAttribute] as? NSURL { + return (value as URL).absoluteString + } + if let value = attributes[markdownImageURLAttribute] as? String, !value.isEmpty { + return value + } + return nil +} + +private func markdownResolveImageSource(_ value: String) -> MarkdownResolvedImageSource { + if value.hasPrefix("//") { + return .remote("https:\(value)") + } + + if value.lowercased().hasPrefix("data:") { + return markdownResolveDataImageSource(value) + } + + guard let url = URL(string: value), let scheme = url.scheme?.lowercased() else { + return .unsupported + } + + switch scheme { + case "http", "https": + return .remote(url.absoluteString) + case "data": + return markdownResolveDataImageSource(url.absoluteString) + default: + return .unsupported + } +} + +private func markdownResolveDataImageSource(_ value: String) -> MarkdownResolvedImageSource { + guard value.lowercased().hasPrefix("data:"), + let commaIndex = value.firstIndex(of: ",") else { + return .unsupported + } + + let header = String(value[value.index(value.startIndex, offsetBy: 5) ..< commaIndex]) + let payloadStart = value.index(after: commaIndex) + let payload = String(value[payloadStart...]) + let isBase64 = header.lowercased().contains(";base64") + + let data: Data? + if isBase64 { + data = Data(base64Encoded: payload, options: [.ignoreUnknownCharacters]) + } else if let decodedPayload = payload.removingPercentEncoding { + data = decodedPayload.data(using: .utf8) + } else { + data = nil + } + + guard let data, + let image = UIImage(data: data), + let dimensions = markdownImagePixelDimensions(image) else { + return .unsupported + } + + return .data(data, dimensions) +} + +private func markdownImagePixelDimensions(_ image: UIImage) -> PixelDimensions? { + if let cgImage = image.cgImage { + return PixelDimensions(width: Int32(cgImage.width), height: Int32(cgImage.height)) + } + + let width = max(1, Int32(ceil(image.size.width * image.scale))) + let height = max(1, Int32(ceil(image.size.height * image.scale))) + return PixelDimensions(width: width, height: height) +} + +private func markdownImageCaption(_ title: String?) -> InstantPageCaption { + if let title, !title.isEmpty { + return InstantPageCaption(text: .plain(title), credit: .empty) + } else { + return InstantPageCaption(text: .empty, credit: .empty) + } +} + +private func markdownInlineImageDimensions(attributes: [NSAttributedString.Key: Any]) -> PixelDimensions { + guard let font = attributes[.font] as? UIFont else { + return markdownDefaultInlineImageDimensions + } + + let side = max(markdownDefaultInlineImageDimensions.width, Int32(ceil(font.lineHeight))) + return PixelDimensions(width: side, height: side) +} + +private func markdownLink(attributes: [NSAttributedString.Key: Any], documentURL: URL) -> String? { + if let value = attributes[markdownLinkAttribute] as? URL { + return markdownNormalizedLink(value, documentURL: documentURL) + } + if let value = attributes[markdownLinkAttribute] as? NSURL { + return markdownNormalizedLink(value as URL, documentURL: documentURL) + } + if let value = attributes[markdownLinkAttribute] as? String, !value.isEmpty { + if value.hasPrefix("#") { + return value + } + if let url = URL(string: value) { + return markdownNormalizedLink(url, documentURL: documentURL) + } + return value + } + return nil +} + +private func markdownNormalizedLink(_ url: URL, documentURL: URL) -> String { + if url.baseURL != nil { + let relative = url.relativeString + if relative.hasPrefix("#") { + return relative + } + } + if let fragment = url.fragment, markdownMatchesDocument(url, documentURL: documentURL) { + return "#\(fragment)" + } + return url.absoluteString +} + +private func markdownMatchesDocument(_ url: URL, documentURL: URL) -> Bool { + let normalizedUrl = markdownURLWithoutFragment(url) + let normalizedDocumentURL = markdownURLWithoutFragment(documentURL) + + if normalizedUrl.isFileURL && normalizedDocumentURL.isFileURL { + return normalizedUrl.standardizedFileURL == normalizedDocumentURL.standardizedFileURL + } else { + return normalizedUrl == normalizedDocumentURL + } +} + +private func markdownURLWithoutFragment(_ url: URL) -> URL { + guard var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { + return url + } + components.fragment = nil + return components.url ?? url +} + +private func markdownCompact(_ fragments: [RichText]) -> RichText { + var compacted: [RichText] = [] + for fragment in fragments { + switch fragment { + case .empty: + continue + case let .plain(text): + guard !text.isEmpty else { + continue + } + if let last = compacted.last, case let .plain(lastText) = last { + compacted[compacted.count - 1] = .plain(lastText + text) + } else { + compacted.append(fragment) + } + case let .concat(items): + let nested = markdownCompact(items) + switch nested { + case .empty: + continue + case let .plain(text): + if let last = compacted.last, case let .plain(lastText) = last { + compacted[compacted.count - 1] = .plain(lastText + text) + } else { + compacted.append(.plain(text)) + } + default: + compacted.append(nested) + } + default: + compacted.append(fragment) + } + } + if compacted.isEmpty { + return .empty + } else if compacted.count == 1 { + return compacted[0] + } else { + return .concat(compacted) + } +} + +private func markdownHasDisplayableContent(_ richText: RichText) -> Bool { + switch richText { + case .empty: + return false + case let .plain(text): + return !text.isEmpty + case let .bold(text), + let .italic(text), + let .underline(text), + let .strikethrough(text), + let .fixed(text), + let .subscript(text), + let .superscript(text), + let .marked(text), + let .anchor(text, _): + return markdownHasDisplayableContent(text) + case let .url(text, _, _), + let .email(text, _), + let .phone(text, _): + return markdownHasDisplayableContent(text) + case let .concat(items): + return items.contains(where: markdownHasDisplayableContent) + case .image: + return true + } +} + +private func markdownIsWhitespaceOnly(_ richText: RichText) -> Bool { + switch richText { + case .empty: + return true + case let .plain(text): + return text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + case let .bold(text), + let .italic(text), + let .underline(text), + let .strikethrough(text), + let .fixed(text), + let .subscript(text), + let .superscript(text), + let .marked(text), + let .anchor(text, _): + return markdownIsWhitespaceOnly(text) + case let .url(text, _, _), + let .email(text, _), + let .phone(text, _): + return markdownIsWhitespaceOnly(text) + case let .concat(items): + return items.allSatisfy(markdownIsWhitespaceOnly) + case .image: + return false + } +} + +private func markdownPlainText(from block: InstantPageBlock) -> String { + switch block { + case let .title(text): + return text.plainText + case let .subtitle(text): + return text.plainText + case let .authorDate(author, _): + return author.plainText + case let .header(text): + return text.plainText + case let .subheader(text): + return text.plainText + case let .paragraph(text): + return text.plainText + case let .preformatted(text): + return text.plainText + case let .footer(text): + return text.plainText + case let .blockQuote(text, caption): + return text.plainText.isEmpty ? caption.plainText : text.plainText + case let .pullQuote(text, caption): + return text.plainText.isEmpty ? caption.plainText : text.plainText + case let .kicker(text): + return text.plainText + case let .table(title, _, _, _): + return title.plainText + case let .details(title, _, _): + return title.plainText + case let .relatedArticles(title, _): + return title.plainText + default: + return "" + } +} + +private func markdownTitle(from blocks: [InstantPageBlock], file: FileMediaReference, fileURL: URL) -> String { + for block in blocks { + if case let .title(text) = block, !text.plainText.isEmpty { + return text.plainText + } + } + if let fileName = file.media.fileName, !fileName.isEmpty { + let baseName = URL(fileURLWithPath: fileName).deletingPathExtension().lastPathComponent + if !baseName.isEmpty { + return baseName + } + return fileName + } + let baseName = fileURL.deletingPathExtension().lastPathComponent + if !baseName.isEmpty { + return baseName + } + return fileURL.lastPathComponent +} + +private func markdownFirstParagraphText(from blocks: [InstantPageBlock]) -> String? { + for block in blocks { + switch block { + case let .paragraph(text): + if !text.plainText.isEmpty { + return text.plainText + } + case let .list(items, _): + for item in items { + switch item { + case let .text(text, _): + if !text.plainText.isEmpty { + return text.plainText + } + case let .blocks(blocks, _): + if let text = markdownFirstParagraphText(from: blocks) { + return text + } + default: + break + } + } + case let .details(_, blocks, _): + if let text = markdownFirstParagraphText(from: blocks) { + return text + } + default: + break + } + } + return nil +} + +private func markdownBlocksWithGeneratedAnchors(_ blocks: [InstantPageBlock]) -> [InstantPageBlock] { + var result: [InstantPageBlock] = [] + var slugCounts: [String: Int] = [:] + + for block in blocks { + if let headingText = markdownHeadingText(from: block), !headingText.isEmpty { + let baseSlug = markdownAnchorSlug(from: headingText) + if !baseSlug.isEmpty { + let count = slugCounts[baseSlug] ?? 0 + slugCounts[baseSlug] = count + 1 + + let slug: String + if count == 0 { + slug = baseSlug + } else { + slug = "\(baseSlug)-\(count)" + } + result.append(.anchor(slug)) + } + } + result.append(block) + } + + return result +} + +private func markdownHeadingText(from block: InstantPageBlock) -> String? { + switch block { + case let .title(text): + return text.plainText + case let .header(text): + return text.plainText + case let .subheader(text): + return text.plainText + default: + return nil + } +} + +private func markdownAnchorSlug(from text: String) -> String { + let normalized = text + .folding(options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive], locale: nil) + .lowercased() + + let dashScalar = "-".unicodeScalars.first! + let separatorSet = CharacterSet.whitespacesAndNewlines.union(CharacterSet(charactersIn: "-_")) + var scalars: [UnicodeScalar] = [] + var previousWasDash = false + + for scalar in normalized.unicodeScalars { + if CharacterSet.alphanumerics.contains(scalar) { + scalars.append(scalar) + previousWasDash = false + } else if separatorSet.contains(scalar) { + if !scalars.isEmpty && !previousWasDash { + scalars.append(dashScalar) + previousWasDash = true + } + } + } + + if scalars.last == dashScalar { + scalars.removeLast() + } + + return String(String.UnicodeScalarView(scalars)) +} + +private func markdownTrimTrailingCodeBlockNewline(_ attributedString: NSAttributedString) -> NSAttributedString { + guard attributedString.length > 0 else { + return attributedString + } + let mutable = NSMutableAttributedString(attributedString: attributedString) + let string = mutable.string + if string.hasSuffix("\r\n"), mutable.length >= 2 { + mutable.deleteCharacters(in: NSRange(location: mutable.length - 2, length: 2)) + } else if string.hasSuffix("\n") { + mutable.deleteCharacters(in: NSRange(location: mutable.length - 1, length: 1)) + } + return mutable +} + +private enum MarkdownIntentKind { + case table([TableHorizontalAlignment]) + case tableHeaderRow + case tableRow + case tableCell(Int) + case paragraph + case header(Int) + case codeBlock(String?) + case thematicBreak + case blockQuote + case unorderedList + case orderedList + case listItem(Int) + case unknown + + @available(iOS 15.0, *) + init(component: PresentationIntent.IntentType) { + switch component.kind { + case let .table(columns): + self = .table(columns.map(markdownTableColumnAlignment)) + case .tableHeaderRow: + self = .tableHeaderRow + case .tableRow(_): + self = .tableRow + case let .tableCell(column): + self = .tableCell(column) + case .paragraph: + self = .paragraph + case let .header(level): + self = .header(level) + case let .codeBlock(languageHint): + self = .codeBlock(languageHint) + case .thematicBreak: + self = .thematicBreak + case .blockQuote: + self = .blockQuote + case .unorderedList: + self = .unorderedList + case .orderedList: + self = .orderedList + case let .listItem(ordinal): + self = .listItem(ordinal) + default: + self = .unknown + } + } +} + +@available(iOS 15.0, *) +private func markdownTableColumnAlignment(_ column: PresentationIntent.TableColumn) -> TableHorizontalAlignment { + switch column.alignment { + case .left: + return .left + case .center: + return .center + case .right: + return .right + @unknown default: + return .left + } +} + +private final class MarkdownIntentNode { + let identity: Int + let kind: MarkdownIntentKind + + private(set) var children: [MarkdownIntentNode] = [] + private var childIdentities: Set = [] + private(set) var attributedText = NSMutableAttributedString(string: "") + + @available(iOS 15.0, *) + init(component: PresentationIntent.IntentType) { + self.identity = component.identity + self.kind = MarkdownIntentKind(component: component) + } + + func append(child: MarkdownIntentNode) { + if self.childIdentities.insert(child.identity).inserted { + self.children.append(child) + } + } + + func append(text: NSAttributedString) { + self.attributedText.append(text) + } +} diff --git a/submodules/BrowserUI/Sources/BrowserPdfContent.swift b/submodules/BrowserUI/Sources/BrowserPdfContent.swift index 89507435b3..0f723e51ef 100644 --- a/submodules/BrowserUI/Sources/BrowserPdfContent.swift +++ b/submodules/BrowserUI/Sources/BrowserPdfContent.swift @@ -364,7 +364,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF let pageIndicatorSize = self.pageIndicator.update( transition: .immediate, component: AnyComponent( - Text(text: "\(self.pageNumber?.0 ?? 1) of \(self.pageNumber?.1 ?? 1)", font: Font.with(size: 15.0, weight: .regular, traits: .monospacedNumbers), color: self.presentationData.theme.list.itemPrimaryTextColor) + Text(text: self.presentationData.strings.Items_NOfM("\(self.pageNumber?.0 ?? 1)", "\(self.pageNumber?.1 ?? 1)").string, font: Font.with(size: 15.0, weight: .regular, traits: .monospacedNumbers), color: self.presentationData.theme.list.itemPrimaryTextColor) ), environment: {}, containerSize: size diff --git a/submodules/BrowserUI/Sources/BrowserScreen.swift b/submodules/BrowserUI/Sources/BrowserScreen.swift index 4349ea6aaa..c93cb4d9f7 100644 --- a/submodules/BrowserUI/Sources/BrowserScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserScreen.swift @@ -29,6 +29,7 @@ private final class BrowserScreenComponent: CombinedComponent { let context: AccountContext let contentState: BrowserContentState? let presentationState: BrowserPresentationState + let toolbarMode: BrowserToolbarMode let canShare: Bool let performAction: ActionSlot let performHoldAction: (UIView, ContextGesture?, BrowserScreen.Action) -> Void @@ -38,6 +39,7 @@ private final class BrowserScreenComponent: CombinedComponent { context: AccountContext, contentState: BrowserContentState?, presentationState: BrowserPresentationState, + toolbarMode: BrowserToolbarMode, canShare: Bool, performAction: ActionSlot, performHoldAction: @escaping (UIView, ContextGesture?, BrowserScreen.Action) -> Void, @@ -46,6 +48,7 @@ private final class BrowserScreenComponent: CombinedComponent { self.context = context self.contentState = contentState self.presentationState = presentationState + self.toolbarMode = toolbarMode self.canShare = canShare self.performAction = performAction self.performHoldAction = performHoldAction @@ -62,6 +65,9 @@ private final class BrowserScreenComponent: CombinedComponent { if lhs.presentationState != rhs.presentationState { return false } + if lhs.toolbarMode != rhs.toolbarMode { + return false + } if lhs.canShare != rhs.canShare { return false } @@ -112,8 +118,7 @@ private final class BrowserScreenComponent: CombinedComponent { navigationLeftItems = [] navigationRightItems = [] } else { - let contentType = context.component.contentState?.contentType ?? .instantPage - switch contentType { + switch context.component.toolbarMode { case .webPage: navigationContent = AnyComponentWithIdentity( id: "addressBar", @@ -131,7 +136,7 @@ private final class BrowserScreenComponent: CombinedComponent { ) ) ) - case .instantPage, .document: + case .instantPage, .document, .markdown: let title = context.component.contentState?.title ?? "" navigationContent = AnyComponentWithIdentity( id: "titleBar_\(title)", @@ -190,47 +195,46 @@ private final class BrowserScreenComponent: CombinedComponent { // ) // ) // #endif - - let canGoBack = context.component.contentState?.canGoBack ?? false - let canGoForward = context.component.contentState?.canGoForward ?? false - - navigationLeftItems.append( - AnyComponentWithIdentity( - id: "back", - component: AnyComponent( - Button( - content: AnyComponent( - BundleIconComponent( - name: "Instant View/Back", - tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoBack ? 1.0 : 0.4) - ) - ), - action: { - performAction.invoke(.navigateBack) - } - ).minSize(CGSize(width: 44.0, height: 44.0)) + if context.component.toolbarMode != .markdown { + let canGoBack = context.component.contentState?.canGoBack ?? false + let canGoForward = context.component.contentState?.canGoForward ?? false + navigationLeftItems.append( + AnyComponentWithIdentity( + id: "back", + component: AnyComponent( + Button( + content: AnyComponent( + BundleIconComponent( + name: "Instant View/Back", + tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoBack ? 1.0 : 0.4) + ) + ), + action: { + performAction.invoke(.navigateBack) + } + ).minSize(CGSize(width: 44.0, height: 44.0)) + ) ) ) - ) - - navigationLeftItems.append( - AnyComponentWithIdentity( - id: "forward", - component: AnyComponent( - Button( - content: AnyComponent( - BundleIconComponent( - name: "Instant View/Forward", - tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoForward ? 1.0 : 0.4) - ) - ), - action: { - performAction.invoke(.navigateForward) - } - ).minSize(CGSize(width: 44.0, height: 44.0)) + navigationLeftItems.append( + AnyComponentWithIdentity( + id: "forward", + component: AnyComponent( + Button( + content: AnyComponent( + BundleIconComponent( + name: "Instant View/Forward", + tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoForward ? 1.0 : 0.4) + ) + ), + action: { + performAction.invoke(.navigateForward) + } + ).minSize(CGSize(width: 44.0, height: 44.0)) + ) ) ) - ) + } } navigationRightItems = [ @@ -258,25 +262,27 @@ private final class BrowserScreenComponent: CombinedComponent { ] if isTablet { - navigationRightItems.insert( - AnyComponentWithIdentity( - id: "bookmarks", - component: AnyComponent( - Button( - content: AnyComponent( - BundleIconComponent( - name: "Instant View/Bookmark", - tintColor: environment.theme.chat.inputPanel.panelControlColor - ) - ), - action: { - performAction.invoke(.openBookmarks) - } - ).minSize(CGSize(width: 44.0, height: 44.0)) - ) - ), - at: 0 - ) + if context.component.toolbarMode != .markdown { + navigationRightItems.insert( + AnyComponentWithIdentity( + id: "bookmarks", + component: AnyComponent( + Button( + content: AnyComponent( + BundleIconComponent( + name: "Instant View/Bookmark", + tintColor: environment.theme.chat.inputPanel.panelControlColor + ) + ), + action: { + performAction.invoke(.openBookmarks) + } + ).minSize(CGSize(width: 44.0, height: 44.0)) + ) + ), + at: 0 + ) + } if context.component.canShare { navigationRightItems.insert( AnyComponentWithIdentity( @@ -369,7 +375,7 @@ private final class BrowserScreenComponent: CombinedComponent { canGoForward: context.component.contentState?.canGoForward ?? false, canOpenIn: canOpenIn, canShare: context.component.canShare, - isDocument: context.component.contentState?.contentType == .document, + mode: context.component.toolbarMode, performAction: performAction, performHoldAction: performHoldAction ) @@ -517,7 +523,45 @@ public class BrowserScreen: ViewController, MinimizableController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? private var validLayout: (ContainerViewLayout, CGFloat)? - + + private var isMarkdownDocument: Bool { + guard let controller = self.controller else { + return false + } + if case .markdownDocument = controller.subject { + return true + } else { + return false + } + } + private var isMarkdownTopLevelContent: Bool { + return self.isMarkdownDocument && self.content.count <= 1 + } + + private var isMarkdownInstantPageContent: Bool { + return self.isMarkdownTopLevelContent && self.content.last is BrowserInstantPageContent + } + + private var toolbarMode: BrowserToolbarMode { + if self.isMarkdownInstantPageContent { + return .markdown + } + switch self.contentState?.contentType { + case .document: + return .document + case .webPage: + return .webPage + case .instantPage: + return .instantPage + case .none: + if self.content.last is BrowserDocumentContent || self.content.last is BrowserPdfContent { + return .document + } else { + return .instantPage + } + } + } + init(controller: BrowserScreen) { self.context = controller.context self.controller = controller @@ -535,7 +579,7 @@ public class BrowserScreen: ViewController, MinimizableController { super.init() self.pushContent(controller.subject, transition: .immediate) - if let content = self.content.last { + if let content = self.content.last, !self.isMarkdownDocument { content.addToRecentlyVisited() } @@ -562,7 +606,44 @@ public class BrowserScreen: ViewController, MinimizableController { let presentationData = self.presentationData let subject: ShareControllerSubject var isDocument = false - if let content = self.content.last { + if let controller = self.controller { + switch controller.subject { + case let .document(file, _), let .pdfDocument(file, _): + subject = .media(file.abstract, nil) + isDocument = true + case let .markdownDocument(file, _): + if self.isMarkdownTopLevelContent { + subject = .media(file.abstract, nil) + isDocument = true + } else if let content = self.content.last { + if let documentContent = content as? BrowserDocumentContent { + subject = .media(documentContent.file.abstract, nil) + isDocument = true + } else if let documentContent = content as? BrowserPdfContent { + subject = .media(documentContent.file.abstract, nil) + isDocument = true + } else { + subject = .url(url) + } + } else { + subject = .url(url) + } + default: + if let content = self.content.last { + if let documentContent = content as? BrowserDocumentContent { + subject = .media(documentContent.file.abstract, nil) + isDocument = true + } else if let documentContent = content as? BrowserPdfContent { + subject = .media(documentContent.file.abstract, nil) + isDocument = true + } else { + subject = .url(url) + } + } else { + subject = .url(url) + } + } + } else if let content = self.content.last { if let documentContent = content as? BrowserDocumentContent { subject = .media(documentContent.file.abstract, nil) isDocument = true @@ -641,7 +722,10 @@ public class BrowserScreen: ViewController, MinimizableController { var processed = false if let controller = self.controller { switch controller.subject { - case let .document(file, canShare), let .pdfDocument(file, canShare): + case let .document(file, canShare), let .pdfDocument(file, canShare), let .markdownDocument(file, canShare): + if case .markdownDocument = controller.subject, !self.isMarkdownTopLevelContent { + break + } processed = true controller.openDocument(file.media, canShare) default: @@ -855,6 +939,20 @@ public class BrowserScreen: ViewController, MinimizableController { browserContent = BrowserDocumentContent(context: self.context, presentationData: self.presentationData, file: file) case let .pdfDocument(file, _): browserContent = BrowserPdfContent(context: self.context, presentationData: self.presentationData, file: file) + case let .markdownDocument(file, _): + if let (webPage, fileURL) = markdownWebpage(context: self.context, file: file) { + browserContent = BrowserInstantPageContent( + context: self.context, + presentationData: self.presentationData, + webPage: webPage, + anchor: nil, + url: fileURL.absoluteString, + sourceLocation: InstantPageSourceLocation(userLocation: .other, peerType: .otherPrivate), + preloadedResouces: nil + ) + } else { + browserContent = BrowserDocumentContent(context: self.context, presentationData: self.presentationData, file: file) + } } browserContent.pushContent = { [weak self] content, additionalContent in guard let self else { @@ -925,6 +1023,10 @@ public class BrowserScreen: ViewController, MinimizableController { } func popContent(transition: ComponentTransition) { + guard self.content.count > 1 else { + return + } + self.content.removeLast() self.requestLayout(transition: transition) @@ -1148,10 +1250,11 @@ public class BrowserScreen: ViewController, MinimizableController { } let canOpenIn = !(self.contentState?.url.hasPrefix("tonsite") ?? false) + let toolbarMode = self.toolbarMode var canShare = true if let controller = self.controller { switch controller.subject { - case let .document(_, canShareValue), let .pdfDocument(_, canShareValue): + case let .document(_, canShareValue), let .pdfDocument(_, canShareValue), let .markdownDocument(_, canShareValue): canShare = canShareValue default: break @@ -1202,7 +1305,7 @@ public class BrowserScreen: ViewController, MinimizableController { }))) } - if [.webPage, .instantPage].contains(contentState.contentType) { + if toolbarMode != .markdown && [.webPage, .instantPage].contains(contentState.contentType) { items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.WebBrowser_AddBookmark, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { (controller, action) in performAction.invoke(.addBookmark) action(.default) @@ -1384,7 +1487,7 @@ public class BrowserScreen: ViewController, MinimizableController { var canShare = true if let controller = self.controller { switch controller.subject { - case let .document(_, canShareValue), let .pdfDocument(_, canShareValue): + case let .document(_, canShareValue), let .pdfDocument(_, canShareValue), let .markdownDocument(_, canShareValue): canShare = canShareValue default: break @@ -1398,6 +1501,7 @@ public class BrowserScreen: ViewController, MinimizableController { context: self.context, contentState: self.contentState, presentationState: self.presentationState, + toolbarMode: self.toolbarMode, canShare: canShare, performAction: self.performAction, performHoldAction: { [weak self] view, gesture, action in @@ -1477,10 +1581,11 @@ public class BrowserScreen: ViewController, MinimizableController { case instantPage(webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation, preloadedResources: [Any]?) case document(file: FileMediaReference, canShare: Bool) case pdfDocument(file: FileMediaReference, canShare: Bool) + case markdownDocument(file: FileMediaReference, canShare: Bool) public var fileId: MediaId? { switch self { - case let .document(file, _), let .pdfDocument(file, _): + case let .document(file, _), let .pdfDocument(file, _), let .markdownDocument(file, _): return file.media.fileId default: return nil @@ -1506,7 +1611,10 @@ public class BrowserScreen: ViewController, MinimizableController { "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.spreadsheetml.template", - "application/vnd.openxmlformats-officedocument.presentationml.presentation" + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "text/markdown", + "text/x-markdown", + "text/x-web-markdown" ] public static let supportedDocumentExtensions: [String] = [ @@ -1517,7 +1625,8 @@ public class BrowserScreen: ViewController, MinimizableController { "docx", "xls", "xlsx", - "pptx" + "pptx", + "md" ] public init(context: AccountContext, subject: Subject, preferredConfiguration: WKWebViewConfiguration? = nil, openPreviousOnClose: Bool = false) { diff --git a/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift b/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift index 5406d1d459..01546e4cd9 100644 --- a/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift @@ -9,6 +9,13 @@ import ContextReferenceButtonComponent import GlassBackgroundComponent import EdgeEffect +enum BrowserToolbarMode: Equatable { + case webPage + case instantPage + case document + case markdown +} + final class BrowserToolbarComponent: CombinedComponent { let theme: PresentationTheme let bottomInset: CGFloat @@ -131,7 +138,7 @@ final class NavigationToolbarContentComponent: CombinedComponent { let canGoForward: Bool let canOpenIn: Bool let canShare: Bool - let isDocument: Bool + let mode: BrowserToolbarMode let performAction: ActionSlot let performHoldAction: (UIView, ContextGesture?, BrowserScreen.Action) -> Void @@ -141,7 +148,7 @@ final class NavigationToolbarContentComponent: CombinedComponent { canGoForward: Bool, canOpenIn: Bool, canShare: Bool, - isDocument: Bool, + mode: BrowserToolbarMode, performAction: ActionSlot, performHoldAction: @escaping (UIView, ContextGesture?, BrowserScreen.Action) -> Void ) { @@ -150,7 +157,7 @@ final class NavigationToolbarContentComponent: CombinedComponent { self.canGoForward = canGoForward self.canOpenIn = canOpenIn self.canShare = canShare - self.isDocument = isDocument + self.mode = mode self.performAction = performAction self.performHoldAction = performHoldAction } @@ -171,7 +178,7 @@ final class NavigationToolbarContentComponent: CombinedComponent { if lhs.canShare != rhs.canShare { return false } - if lhs.isDocument != rhs.isDocument { + if lhs.mode != rhs.mode { return false } return true @@ -217,7 +224,8 @@ final class NavigationToolbarContentComponent: CombinedComponent { transition: .easeInOut(duration: 0.2) ) - if context.component.isDocument { + switch context.component.mode { + case .document: var originX: CGFloat = sideInset let search = search.update( @@ -270,7 +278,40 @@ final class NavigationToolbarContentComponent: CombinedComponent { .position(CGPoint(x: originX, y: availableSize.height / 2.0)) ) size.width = originX + sideInset - } else { + case .markdown: + var originX: CGFloat = sideInset + + if !context.component.canShare { + context.add(share + .position(CGPoint(x: availableSize.width / 2.0, y: 10000.0)) + ) + } else { + context.add(share + .position(CGPoint(x: originX, y: availableSize.height / 2.0)) + ) + originX += spacing + } + + let quickLook = quickLook.update( + component: Button( + content: AnyComponent( + BundleIconComponent( + name: "Instant View/OpenDocument", + tintColor: textColor + ) + ), + action: { + performAction.invoke(.openIn) + } + ).minSize(buttonSize), + availableSize: buttonSize, + transition: .easeInOut(duration: 0.2) + ) + context.add(quickLook + .position(CGPoint(x: originX, y: availableSize.height / 2.0)) + ) + size.width = originX + sideInset + case .webPage, .instantPage: var originX: CGFloat = sideInset let canGoBack = context.component.canGoBack diff --git a/submodules/BrowserUI/Sources/Utils.swift b/submodules/BrowserUI/Sources/Utils.swift index 71489f05a3..fe17f25240 100644 --- a/submodules/BrowserUI/Sources/Utils.swift +++ b/submodules/BrowserUI/Sources/Utils.swift @@ -23,8 +23,6 @@ func fetchFavicon(context: AccountContext, url: String, size: CGSize) -> Signal< if let data { if let image = UIImage(data: data) { return image - } else if url.lowercased().contains(".svg"), let preparedData = prepareSvgImage(data, false), let image = renderPreparedImage(preparedData, size, .clear, UIScreenScale, false) { - return image } return nil } else { diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index e7e05ee43c..91962df4e2 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2384,11 +2384,8 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var currentStatusIconContent: EmojiStatusComponent.Content? var currentStatusIconParticleColor: UIColor? var currentSecretIconImage: UIImage? - var currentForwardedIcon: UIImage? - var currentStoryIcon: UIImage? - var currentGiftIcon: UIImage? - var currentLocationIcon: UIImage? - var currentPollIcon: UIImage? + var currentMessageTypeIcon: UIImage? + var currentMessageTypeIconOffset: CGPoint = .zero var selectableControlSizeAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? var reorderControlSizeAndApply: (CGFloat, (CGFloat, Bool, ContainedViewLayoutTransition) -> ItemListEditableReorderControlNode)? @@ -2559,12 +2556,26 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var contentImageSpecs: [ContentImageSpec] = [] var avatarContentImageSpec: ContentImageSpec? var forumThread: (id: Int64, title: String, iconId: Int64?, iconColor: Int32, threadPeer: EnginePeer?, isUnread: Bool)? - - var displayForwardedIcon = false - var displayStoryReplyIcon = false - var displayGiftIcon = false - var displayLocationIcon = false - var displayPollIcon = false + + enum MessageTypeIcon { + enum CallType { + case voice + case video + } + enum CallDirection { + case incoming + case outgoing + } + case call(CallType, CallDirection) + case forward + case story + case gift + case location + case poll + case todo + case game + } + var messageTypeIcon: MessageTypeIcon? var ignoreForwardedIcon = false switch contentData { @@ -2874,24 +2885,29 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { if !ignoreForwardedIcon { if case .savedMessagesChats = item.chatListLocation { - displayForwardedIcon = false } else if let forwardInfo = message.forwardInfo, !forwardInfo.flags.contains(.isImported) && !message.id.peerId.isVerificationCodes { - displayForwardedIcon = true + messageTypeIcon = .forward } else if let _ = message.attributes.first(where: { $0 is ReplyStoryAttribute }) { - displayStoryReplyIcon = true + messageTypeIcon = .story } else { for media in message.media { if let _ = media as? TelegramMediaPoll { - displayPollIcon = true + messageTypeIcon = .poll + } else if let _ = media as? TelegramMediaTodo { + messageTypeIcon = .todo + } else if let _ = media as? TelegramMediaGame { + messageTypeIcon = .game } else if let _ = media as? TelegramMediaMap { - displayLocationIcon = true + messageTypeIcon = .location } else if let action = media as? TelegramMediaAction { switch action.action { + case let .phoneCall(_, _, _, isVideo): + messageTypeIcon = .call(isVideo ? .video : .voice, message.flags.contains(.Incoming) ? .incoming : .outgoing) case .giftPremium, .giftStars, .starGift, .starGiftUnique: - displayGiftIcon = true + messageTypeIcon = .gift case let .giftCode(_, _, _, boostPeerId, _, _, _, _, _, _, _): if boostPeerId == nil { - displayGiftIcon = true + messageTypeIcon = .gift } default: break @@ -3048,64 +3064,50 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { attributedText = textString } - if displayForwardedIcon { - currentForwardedIcon = PresentationResourcesChatList.forwardedIcon(item.presentationData.theme) - } - - if displayStoryReplyIcon { - currentStoryIcon = PresentationResourcesChatList.storyReplyIcon(item.presentationData.theme) - } - - if displayGiftIcon { - currentGiftIcon = PresentationResourcesChatList.giftIcon(item.presentationData.theme) - } - - if displayLocationIcon { - currentLocationIcon = PresentationResourcesChatList.locationIcon(item.presentationData.theme) - } - - if displayPollIcon { - currentPollIcon = PresentationResourcesChatList.pollIcon(item.presentationData.theme) - } - - if let currentForwardedIcon { - textLeftCutout += currentForwardedIcon.size.width - if !contentImageSpecs.isEmpty { - textLeftCutout += forwardedIconSpacing - } else { - textLeftCutout += contentImageTrailingSpace + switch messageTypeIcon { + case let .call(type, direction): + switch type { + case .voice: + switch direction { + case .incoming: + currentMessageTypeIcon = PresentationResourcesChatList.callIncomingIcon(item.presentationData.theme) + case .outgoing: + currentMessageTypeIcon = PresentationResourcesChatList.callOutgoingIcon(item.presentationData.theme) + } + case .video: + switch direction { + case .incoming: + currentMessageTypeIcon = PresentationResourcesChatList.callVideoIncomingIcon(item.presentationData.theme) + case .outgoing: + currentMessageTypeIcon = PresentationResourcesChatList.callVideoOutgoingIcon(item.presentationData.theme) + } } + case .forward: + currentMessageTypeIcon = PresentationResourcesChatList.forwardedIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = 3.0 + case .story: + currentMessageTypeIcon = PresentationResourcesChatList.storyReplyIcon(item.presentationData.theme) + case .gift: + currentMessageTypeIcon = PresentationResourcesChatList.giftIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = -2.0 - UIScreenPixel + case .location: + currentMessageTypeIcon = PresentationResourcesChatList.locationIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = -1.0 - UIScreenPixel + case .poll: + currentMessageTypeIcon = PresentationResourcesChatList.pollIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = -1.0 + case .todo: + currentMessageTypeIcon = PresentationResourcesChatList.todoIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = -1.0 + case .game: + currentMessageTypeIcon = PresentationResourcesChatList.gameIcon(item.presentationData.theme) + currentMessageTypeIconOffset.y = -1.0 + default: + break } - if let currentStoryIcon { - textLeftCutout += currentStoryIcon.size.width - if !contentImageSpecs.isEmpty { - textLeftCutout += forwardedIconSpacing - } else { - textLeftCutout += contentImageTrailingSpace - } - } - - if let currentGiftIcon { - textLeftCutout += currentGiftIcon.size.width - if !contentImageSpecs.isEmpty { - textLeftCutout += forwardedIconSpacing - } else { - textLeftCutout += contentImageTrailingSpace - } - } - - if let currentLocationIcon { - textLeftCutout += currentLocationIcon.size.width - if !contentImageSpecs.isEmpty { - textLeftCutout += forwardedIconSpacing - } else { - textLeftCutout += contentImageTrailingSpace - } - } - - if let currentPollIcon { - textLeftCutout += currentPollIcon.size.width + if let currentMessageTypeIcon { + textLeftCutout += currentMessageTypeIcon.size.width if !contentImageSpecs.isEmpty { textLeftCutout += forwardedIconSpacing } else { @@ -4765,31 +4767,16 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var mediaPreviewOffset = textNodeFrame.origin.offsetBy(dx: 1.0, dy: 1.0 + floor((measureLayout.size.height - contentImageSize.height) / 2.0)) - var messageTypeIcon: UIImage? - var messageTypeIconOffset = mediaPreviewOffset - if let currentForwardedIcon { - messageTypeIcon = currentForwardedIcon - messageTypeIconOffset.y += 3.0 - } else if let currentStoryIcon { - messageTypeIcon = currentStoryIcon - } else if let currentGiftIcon { - messageTypeIcon = currentGiftIcon - messageTypeIconOffset.y -= 2.0 - UIScreenPixel - } else if let currentLocationIcon { - messageTypeIcon = currentLocationIcon - messageTypeIconOffset.y -= 2.0 - UIScreenPixel - } else if let currentPollIcon { - messageTypeIcon = currentPollIcon - messageTypeIconOffset.y -= 2.0 - UIScreenPixel - } + let messageTypeIconImage = currentMessageTypeIcon + let messageTypeIconOffset = CGPoint(x: mediaPreviewOffset.x + currentMessageTypeIconOffset.x, y: mediaPreviewOffset.y + currentMessageTypeIconOffset.y) - if let messageTypeIcon { - strongSelf.forwardedIconNode.image = messageTypeIcon + if let messageTypeIconImage { + strongSelf.forwardedIconNode.image = messageTypeIconImage if strongSelf.forwardedIconNode.supernode == nil { strongSelf.mainContentContainerNode.addSubnode(strongSelf.forwardedIconNode) } - transition.updateFrame(node: strongSelf.forwardedIconNode, frame: CGRect(origin: messageTypeIconOffset, size: messageTypeIcon.size)) - mediaPreviewOffset.x += messageTypeIcon.size.width + forwardedIconSpacing + transition.updateFrame(node: strongSelf.forwardedIconNode, frame: CGRect(origin: messageTypeIconOffset, size: messageTypeIconImage.size)) + mediaPreviewOffset.x += messageTypeIconImage.size.width + forwardedIconSpacing } else if strongSelf.forwardedIconNode.supernode != nil { strongSelf.forwardedIconNode.removeFromSupernode() } diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 824887b5d4..05fe3b01f8 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -311,7 +311,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: case _ as TelegramMediaContact: messageText = strings.Message_Contact case let game as TelegramMediaGame: - messageText = "🎮 \(game.title)" + messageText = game.title case let invoice as TelegramMediaInvoice: messageText = invoice.title case let action as TelegramMediaAction: @@ -438,15 +438,11 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: messageText = content.displayUrl } case let todo as TelegramMediaTodo: - let pollPrefix = "☑️ " - let entityOffset = (pollPrefix as NSString).length - messageText = "\(pollPrefix)\(todo.text)" + messageText = todo.text + customEmojiRanges = [] for entity in todo.textEntities { if case let .CustomEmoji(_, fileId) = entity.type { - if customEmojiRanges == nil { - customEmojiRanges = [] - } - let range = NSRange(location: entityOffset + entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) + let range = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) let attribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: message.associatedMedia[EngineMedia.Id(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile) customEmojiRanges?.append((range, attribute)) } diff --git a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift index 42d00f8d85..5ae4f9ddcc 100644 --- a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift +++ b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift @@ -383,8 +383,15 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent private var iconFrame: CGRect? private var file: TelegramMediaFile? private var fileDisposable: Disposable? + private var longTapRecognizer: UILongPressGestureRecognizer? + private var skipNextTapAction = false let action: () -> Void + var longTapAction: (() -> Void)? { + didSet { + self.longTapRecognizer?.isEnabled = self.longTapAction != nil + } + } private var item: EngineMessageReactionListContext.Item? @@ -422,6 +429,12 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent self.view.addSubview(self.readIconView) self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside) + + let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longTapGesture(_:))) + longTapRecognizer.isEnabled = false + longTapRecognizer.cancelsTouchesInView = true + self.view.addGestureRecognizer(longTapRecognizer) + self.longTapRecognizer = longTapRecognizer } deinit { @@ -429,9 +442,30 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent } @objc private func pressed() { + if self.skipNextTapAction { + self.skipNextTapAction = false + return + } self.action() } + @objc private func longTapGesture(_ recognizer: UILongPressGestureRecognizer) { + switch recognizer.state { + case .began: + guard let item = self.item, item.reaction != nil else { + return + } + self.skipNextTapAction = true + self.longTapAction?() + case .cancelled, .ended, .failed: + DispatchQueue.main.async { [weak self] in + self?.skipNextTapAction = false + } + default: + break + } + } + private func updateReactionLayer() { guard let file = self.file else { return @@ -771,6 +805,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent private let requestUpdate: (ReactionsTabNode, ContainedViewLayoutTransition) -> Void private let requestUpdateApparentHeight: (ReactionsTabNode, ContainedViewLayoutTransition) -> Void private let openPeer: (EnginePeer, Bool) -> Void + private let deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? private var hasMore: Bool = false @@ -804,7 +839,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent readStats: MessageReadStats?, requestUpdate: @escaping (ReactionsTabNode, ContainedViewLayoutTransition) -> Void, requestUpdateApparentHeight: @escaping (ReactionsTabNode, ContainedViewLayoutTransition) -> Void, - openPeer: @escaping (EnginePeer, Bool) -> Void + openPeer: @escaping (EnginePeer, Bool) -> Void, + deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? ) { self.context = context self.displayReadTimestamps = displayReadTimestamps @@ -816,6 +852,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent self.requestUpdate = requestUpdate self.requestUpdateApparentHeight = requestUpdateApparentHeight self.openPeer = openPeer + self.deleteReaction = deleteReaction self.listContext = context.engine.messages.messageReactionList(message: message, readStats: readStats, reaction: reaction) self.state = ItemsState(listState: EngineMessageReactionListContext.State(message: message, readStats: readStats, reaction: reaction), readStats: readStats) @@ -928,6 +965,14 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent } itemNode.update(size: itemFrame.size, presentationData: presentationData, item: item, isLast: self.state.item(at: index + 1) == nil, syncronousLoad: syncronousLoad) + if let deleteReaction = self.deleteReaction, let reaction = item.reaction { + let peer = item.peer + itemNode.longTapAction = { + deleteReaction(peer, reaction) + } + } else { + itemNode.longTapAction = nil + } itemNode.frame = itemFrame } else if index < self.state.totalCount { validPlaceholderIds.insert(index) @@ -1079,6 +1124,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent private let reactions: [(MessageReaction.Reaction?, Int)] private let requestUpdate: (ContainedViewLayoutTransition) -> Void private let requestUpdateApparentHeight: (ContainedViewLayoutTransition) -> Void + private let deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? private var presentationData: PresentationData @@ -1111,7 +1157,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateApparentHeight: @escaping (ContainedViewLayoutTransition) -> Void, back: (() -> Void)?, - openPeer: @escaping (EnginePeer, Bool) -> Void + openPeer: @escaping (EnginePeer, Bool) -> Void, + deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? ) { self.context = context self.displayReadTimestamps = displayReadTimestamps @@ -1126,6 +1173,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent self.requestUpdate = requestUpdate self.requestUpdateApparentHeight = requestUpdateApparentHeight + self.deleteReaction = deleteReaction if let back = back { self.backButtonNode = BackButtonNode() @@ -1332,7 +1380,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent strongSelf.requestUpdateApparentHeight(transition) } }, - openPeer: self.openPeer + openPeer: self.openPeer, + deleteReaction: self.deleteReaction ) self.addSubnode(tabNode) self.visibleTabNodes[index] = tabNode @@ -1426,6 +1475,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent let readStats: MessageReadStats? let back: (() -> Void)? let openPeer: (EnginePeer, Bool) -> Void + let deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? public init( context: AccountContext, @@ -1437,7 +1487,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent reaction: MessageReaction.Reaction?, readStats: MessageReadStats?, back: (() -> Void)?, - openPeer: @escaping (EnginePeer, Bool) -> Void + openPeer: @escaping (EnginePeer, Bool) -> Void, + deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)? = nil ) { self.context = context self.displayReadTimestamps = displayReadTimestamps @@ -1449,6 +1500,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent self.readStats = readStats self.back = back self.openPeer = openPeer + self.deleteReaction = deleteReaction } public func node( @@ -1467,7 +1519,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent requestUpdate: requestUpdate, requestUpdateApparentHeight: requestUpdateApparentHeight, back: self.back, - openPeer: self.openPeer + openPeer: self.openPeer, + deleteReaction: self.deleteReaction ) } } diff --git a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift index eda1e61c23..3bd4728b38 100644 --- a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift +++ b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift @@ -13,7 +13,7 @@ public final class ResizableSheetComponentEnvironment: Equatable { public let bounds: CGRect public let isInteractive: Bool } - + public let theme: PresentationTheme public let statusBarHeight: CGFloat public let safeInsets: UIEdgeInsets @@ -26,7 +26,7 @@ public final class ResizableSheetComponentEnvironment: Equatable { public let regularMetricsSize: CGSize? public let dismiss: (Bool) -> Void public let boundsUpdated: ActionSlot - + public init( theme: PresentationTheme, statusBarHeight: CGFloat, @@ -54,7 +54,7 @@ public final class ResizableSheetComponentEnvironment: Equatable { self.dismiss = dismiss self.boundsUpdated = boundsUpdated } - + public static func ==(lhs: ResizableSheetComponentEnvironment, rhs: ResizableSheetComponentEnvironment) -> Bool { if lhs.theme != rhs.theme { return false @@ -92,19 +92,24 @@ public final class ResizableSheetComponentEnvironment: Equatable { public final class ResizableSheetComponent: Component { public typealias EnvironmentType = (ChildEnvironmentType, ResizableSheetComponentEnvironment) - + public class ExternalState { public fileprivate(set) var contentHeight: CGFloat - + fileprivate var trackedScrollViewUpdated: ((UIScrollView?) -> Void)? + public init() { self.contentHeight = 0.0 } + + public func setTrackedScrollView(_ scrollView: UIScrollView?) { + self.trackedScrollViewUpdated?(scrollView) + } } - + public enum BackgroundColor: Equatable { case color(UIColor) } - + public let content: AnyComponent public let titleItem: AnyComponent? public let leftItem: AnyComponent? @@ -113,9 +118,10 @@ public final class ResizableSheetComponent? public let backgroundColor: BackgroundColor public let isFullscreen: Bool + public let defaultHeight: CGFloat? public let externalState: ExternalState? public let animateOut: ActionSlot> - + public init( content: AnyComponent, titleItem: AnyComponent? = nil, @@ -125,6 +131,7 @@ public final class ResizableSheetComponent? = nil, backgroundColor: BackgroundColor, isFullscreen: Bool = false, + defaultHeight: CGFloat? = nil, externalState: ExternalState? = nil, animateOut: ActionSlot>, ) { @@ -136,10 +143,11 @@ public final class ResizableSheetComponent Bool { if lhs.content != rhs.content { return false @@ -165,12 +173,15 @@ public final class ResizableSheetComponent UIView? { return super.hitTest(point, with: event) } } - + public final class View: UIView, UIScrollViewDelegate, ComponentTaggedView, UIGestureRecognizerDelegate { public final class Tag { public init() { } } - + public func matches(tag: Any) -> Bool { if let _ = tag as? Tag { return true } return false } - + private let dimView: UIView public let containerView: UIView private let backgroundLayer: SimpleLayer @@ -218,54 +229,57 @@ public final class ResizableSheetComponent - + private var titleItemView: ComponentView? private var leftItemView: ComponentView? private var rightItemView: ComponentView? private var bottomItemView: ComponentView? - + private let backgroundHandleView: UIImageView - + private var ignoreScrolling: Bool = false private var isDismissingInteractively: Bool = false private var dismissTranslation: CGFloat = 0.0 private var dismissStartTranslation: CGFloat? private var dismissPanGesture: UIPanGestureRecognizer? - + private var component: ResizableSheetComponent? private weak var state: EmptyComponentState? private var isUpdating: Bool = false private var environment: ResizableSheetComponentEnvironment? private var itemLayout: ItemLayout? - + private var registeredExternalState: ExternalState? + private weak var trackedScrollView: UIScrollView? + private var trackedScrollViewWasAtTopOnGestureBegan = false + override init(frame: CGRect) { self.dimView = UIView() self.containerView = UIView() - + self.containerView.clipsToBounds = true self.containerView.layer.cornerRadius = 40.0 self.containerView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] - + self.backgroundLayer = SimpleLayer() self.backgroundLayer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] self.backgroundLayer.cornerRadius = 40.0 - + self.backgroundHandleView = UIImageView() - + self.navigationBarContainer = SparseContainerView() self.bottomContainer = SparseContainerView() - + self.scrollView = ScrollView() - + self.scrollContentClippingView = SparseContainerView() self.scrollContentClippingView.clipsToBounds = true - + self.scrollContentView = UIView() - + self.topEdgeEffectView = EdgeEffectView() self.topEdgeEffectView.clipsToBounds = true self.topEdgeEffectView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] @@ -275,15 +289,16 @@ public final class ResizableSheetComponent UIView? { if !self.bounds.contains(point) { return nil @@ -331,7 +351,7 @@ public final class ResizableSheetComponent Bool { if gestureRecognizer === self.dismissPanGesture { let pan = gestureRecognizer as! UIPanGestureRecognizer @@ -352,22 +372,25 @@ public final class ResizableSheetComponent Bool { if gestureRecognizer === self.dismissPanGesture { if otherGestureRecognizer === self.scrollView.panGestureRecognizer { return true } + if otherGestureRecognizer === self.trackedScrollView?.panGestureRecognizer { + return true + } } return false } - + @objc private func dimTapGesture(_ recognizer: UITapGestureRecognizer) { if case .ended = recognizer.state { self.dismissAnimated() } } - + public func dismissAnimated() { guard let environment = self.environment else { return @@ -375,16 +398,16 @@ public final class ResizableSheetComponent threshold || velocityY > 1000.0 - + self.isDismissingInteractively = false self.scrollView.isScrollEnabled = !component.isFullscreen - + if shouldDismiss { let animateOffset = self.bounds.height - self.backgroundLayer.frame.minY let initialVelocity = animateOffset > 0.0 ? max(0.0, velocityY) / animateOffset : 0.0 @@ -448,73 +471,170 @@ public final class ResizableSheetComponent CGFloat { + return -scrollView.contentInset.top + } + + private func isSheetFullyExpanded(itemLayout: ItemLayout) -> Bool { + return itemLayout.topInset <= 0.5 || self.scrollView.contentOffset.y >= itemLayout.topInset - 0.5 + } + + private func pinTrackedScrollViewToTop(_ scrollView: UIScrollView) { + let topOffset = self.trackedScrollViewTopOffset(scrollView) + if abs(scrollView.contentOffset.y - topOffset) > 0.5 { + scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: topOffset) + } + } + + private func updateTrackedScrollViewLock() { + guard let component = self.component, let itemLayout = self.itemLayout, let trackedScrollView = self.trackedScrollView else { + return + } + trackedScrollView.isScrollEnabled = true + if component.isFullscreen { + return + } + if !self.isSheetFullyExpanded(itemLayout: itemLayout) || self.isDismissingInteractively { + self.pinTrackedScrollViewToTop(trackedScrollView) + } + } + + private func setTrackedScrollView(_ scrollView: UIScrollView?) { + if self.trackedScrollView === scrollView { + self.updateTrackedScrollViewLock() + return + } + + if let trackedScrollView = self.trackedScrollView { + trackedScrollView.panGestureRecognizer.removeTarget(self, action: #selector(self.trackedScrollViewPanGesture(_:))) + trackedScrollView.isScrollEnabled = true + } + + self.trackedScrollView = scrollView + + if let scrollView = scrollView { + scrollView.panGestureRecognizer.addTarget(self, action: #selector(self.trackedScrollViewPanGesture(_:))) + } + + self.trackedScrollViewWasAtTopOnGestureBegan = false + self.updateTrackedScrollViewLock() + } + + @objc private func trackedScrollViewPanGesture(_ recognizer: UIPanGestureRecognizer) { + guard let component = self.component, let itemLayout = self.itemLayout, let trackedScrollView = recognizer.view as? UIScrollView else { + return + } + guard !component.isFullscreen, itemLayout.topInset > 0.5 else { + return + } + + let topOffset = self.trackedScrollViewTopOffset(trackedScrollView) + let isAtTop = trackedScrollView.contentOffset.y <= topOffset + 8.0 + + switch recognizer.state { + case .began, .changed: + if recognizer.state == .began { + self.trackedScrollViewWasAtTopOnGestureBegan = isAtTop + } + let translation = recognizer.translation(in: trackedScrollView) + let currentSheetOffset = min(max(0.0, self.scrollView.contentOffset.y), itemLayout.topInset) + let shouldExpandSheet = self.trackedScrollViewWasAtTopOnGestureBegan && currentSheetOffset < itemLayout.topInset - 0.5 + + if translation.y < 0.0 && shouldExpandSheet { + let consumedOffset = min(itemLayout.topInset - currentSheetOffset, -translation.y) + if consumedOffset > 0.0 { + self.scrollView.contentOffset = CGPoint(x: self.scrollView.contentOffset.x, y: currentSheetOffset + consumedOffset) + self.pinTrackedScrollViewToTop(trackedScrollView) + recognizer.setTranslation(.zero, in: trackedScrollView) + } + } else if translation.y > 0.0 && isAtTop && currentSheetOffset > 0.5 { + let consumedOffset = min(currentSheetOffset, translation.y) + if consumedOffset > 0.0 { + self.scrollView.contentOffset = CGPoint(x: self.scrollView.contentOffset.x, y: currentSheetOffset - consumedOffset) + self.pinTrackedScrollViewToTop(trackedScrollView) + recognizer.setTranslation(.zero, in: trackedScrollView) + } + } else if self.isDismissingInteractively || (translation.y > 0.0 && isAtTop && currentSheetOffset <= 0.5) { + self.pinTrackedScrollViewToTop(trackedScrollView) + } + case .ended, .cancelled, .failed: + self.trackedScrollViewWasAtTopOnGestureBegan = false + if !self.isSheetFullyExpanded(itemLayout: itemLayout) || self.isDismissingInteractively { + self.pinTrackedScrollViewToTop(trackedScrollView) + } + default: + break + } + } + private func updateScrolling(transition: ComponentTransition) { - guard let itemLayout = self.itemLayout, let component = self.component else { + guard let itemLayout = self.itemLayout, let component = self.component, let environment = self.environment else { return } var topOffset = -self.scrollView.bounds.minY + itemLayout.topInset topOffset = max(0.0, topOffset) transition.setTransform(layer: self.backgroundLayer, transform: CATransform3DMakeTranslation(0.0, topOffset + itemLayout.containerInset, 0.0)) - + transition.setPosition(view: self.navigationBarContainer, position: CGPoint(x: 0.0, y: topOffset + itemLayout.containerInset)) - + var topOffsetFraction = self.scrollView.bounds.minY / 100.0 topOffsetFraction = max(0.0, min(1.0, topOffsetFraction)) - - if component.isFullscreen { + + if component.isFullscreen || environment.inputHeight > 0.0 { topOffsetFraction = 1.0 } - #if DEBUG// && false - if "".isEmpty { - topOffsetFraction = 1.0 - } - #endif - +// #if DEBUG// && false +// if "".isEmpty { +// topOffsetFraction = 1.0 +// } +// #endif + let minScale: CGFloat = itemLayout.isTablet ? 1.0 : (itemLayout.containerSize.width - 6.0 * 2.0) / itemLayout.containerSize.width let minScaledTranslation: CGFloat = itemLayout.isTablet ? 0.0 : (itemLayout.containerSize.height - itemLayout.containerSize.height * minScale) * 0.5 - 6.0 let minScaledCornerRadius: CGFloat = itemLayout.containerCornerRadius - + let scale = minScale * (1.0 - topOffsetFraction) + 1.0 * topOffsetFraction let scaledTranslation = minScaledTranslation * (1.0 - topOffsetFraction) let scaledCornerRadius = minScaledCornerRadius * (1.0 - topOffsetFraction) + itemLayout.containerCornerRadius * topOffsetFraction - + var containerTransform = CATransform3DIdentity containerTransform = CATransform3DTranslate(containerTransform, 0.0, scaledTranslation, 0.0) containerTransform = CATransform3DScale(containerTransform, scale, scale, scale) containerTransform = CATransform3DTranslate(containerTransform, 0.0, self.dismissTranslation, 0.0) transition.setTransform(view: self.containerView, transform: containerTransform) transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: scaledCornerRadius) - + if component.isFullscreen { transition.setBounds(view: self.scrollView, bounds: CGRect(origin: .zero, size: self.scrollView.bounds.size)) self.scrollView.isScrollEnabled = false } else { self.scrollView.isScrollEnabled = !self.isDismissingInteractively } - + var bounds = self.scrollView.bounds bounds.size.width = itemLayout.fillingSize self.environment?.boundsUpdated.invoke(ResizableSheetComponentEnvironment.BoundsUpdate(bounds: bounds, isInteractive: self.scrollView.isTracking)) + self.updateTrackedScrollViewLock() } - + private var didPlayAppearanceAnimation = false func animateIn() { self.didPlayAppearanceAnimation = true - + self.dimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) let animateOffset: CGFloat = self.bounds.height - self.backgroundLayer.frame.minY self.containerView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) } - + func animateOut(initialVelocity: CGFloat? = nil, completion: @escaping () -> Void) { let animateOffset: CGFloat = self.bounds.height - self.backgroundLayer.frame.minY - + self.dimView.layer.animateAlpha(from: self.dimView.alpha, to: 0.0, duration: 0.3, removeOnCompletion: false) if let initialVelocity = initialVelocity { let transition = ContainedViewLayoutTransition.animated(duration: 0.35, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity)) - + transition.updatePosition(layer: self.containerView.layer, position: CGPoint(x: self.containerView.layer.position.x, y: self.containerView.layer.position.y + animateOffset), completion: { _ in completion() }) @@ -525,13 +645,13 @@ public final class ResizableSheetComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.isUpdating = true defer { self.isUpdating = false } - + let sheetEnvironment = environment[ResizableSheetComponentEnvironment.self].value component.animateOut.connect { [weak self] completion in guard let self else { @@ -541,9 +661,9 @@ public final class ResizableSheetComponent 0.0 { + initialContentHeight = contentHeight + } else if let defaultHeight = component.defaultHeight { + initialContentHeight = min(contentHeight, max(0.0, defaultHeight)) + } else { + initialContentHeight = contentHeight + } + let edgeEffectHeight: CGFloat = 80.0 let edgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: 0.0), size: CGSize(width: fillingSize, height: edgeEffectHeight)) transition.setFrame(view: self.topEdgeEffectView, frame: edgeEffectFrame) @@ -615,7 +754,7 @@ public final class ResizableSheetComponent if let current = self.titleItemView { @@ -624,12 +763,12 @@ public final class ResizableSheetComponent() self.titleItemView = titleItemView } - + let titleItemSize = titleItemView.update( transition: transition, component: titleItem, environment: {}, - containerSize: CGSize(width: containerSize.width - 66.0 * 2.0, height: 66.0) + containerSize: CGSize(width: containerSize.width - 72.0 * 2.0, height: 66.0) ) let titleItemFrame = CGRect(origin: CGPoint(x: rawSideInset + floorToScreenPixels((containerSize.width - titleItemSize.width)) / 2.0, y: floorToScreenPixels(38.0 - titleItemSize.height * 0.5)), size: titleItemSize) if let view = titleItemView.view { @@ -642,7 +781,7 @@ public final class ResizableSheetComponent @@ -653,7 +792,7 @@ public final class ResizableSheetComponent() self.leftItemView = leftItemView } - + let leftItemSize = leftItemView.update( transition: leftItemTransition, component: leftItem, @@ -664,7 +803,7 @@ public final class ResizableSheetComponent @@ -694,7 +833,7 @@ public final class ResizableSheetComponent() self.rightItemView = rightItemView } - + let rightItemSize = rightItemView.update( transition: rightItemTransition, component: rightItem, @@ -705,7 +844,7 @@ public final class ResizableSheetComponent 0.0 { bottomInsets.left = 16.0 bottomInsets.right = 16.0 bottomInsets.bottom = sheetEnvironment.inputHeight + 8.0 } - + + var bottomEdgeEffectHeight = edgeEffectHeight if let bottomItem = component.bottomItem { var bottomItemTransition = transition let bottomItemView: ComponentView @@ -742,7 +882,7 @@ public final class ResizableSheetComponent() self.bottomItemView = bottomItemView } - + let bottomItemSize = bottomItemView.update( transition: bottomItemTransition, component: bottomItem, @@ -753,7 +893,7 @@ public final class ResizableSheetComponent View { return View(frame: CGRect()) } - + public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 6959fa0430..9c6b20390a 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -602,6 +602,7 @@ public enum ContextControllerTip: Equatable { case starsReactions(topCount: Int) case videoProcessing case collageReordering + case deleteReaction public static func ==(lhs: ContextControllerTip, rhs: ContextControllerTip) -> Bool { switch lhs { @@ -611,6 +612,12 @@ public enum ContextControllerTip: Equatable { } else { return false } + case .deleteReaction: + if case .deleteReaction = rhs { + return true + } else { + return false + } case .quoteSelection: if case .quoteSelection = rhs { return true diff --git a/submodules/InstantPageUI/Sources/InstantPageContentNode.swift b/submodules/InstantPageUI/Sources/InstantPageContentNode.swift index 71505c13ee..debdbc8044 100644 --- a/submodules/InstantPageUI/Sources/InstantPageContentNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageContentNode.swift @@ -9,7 +9,7 @@ import TelegramUIPreferences import AccountContext import ContextUI -public final class InstantPageContentNode : ASDisplayNode { +public final class InstantPageContentNode : ASDisplayNode, InstantPageExternalMediaDimensionsNode { private let context: AccountContext private let strings: PresentationStrings private let nameDisplayOrder: PresentationPersonNameOrder @@ -29,13 +29,20 @@ public final class InstantPageContentNode : ASDisplayNode { var distanceThresholdGroupCount: [Int: Int] = [:] var visibleTiles: [Int: InstantPageTileNode] = [:] - var visibleItemsWithNodes: [Int: InstantPageNode] = [:] + public var visibleItemsWithNodes: [Int: InstantPageNode] = [:] var currentWebEmbedHeights: [Int : CGFloat] = [:] - var currentExpandedDetails: [Int : Bool]? + public var currentExpandedDetails: [Int : Bool]? var currentDetailsItems: [InstantPageDetailsItem] = [] var requestLayoutUpdate: ((Bool) -> Void)? + public var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? { + didSet { + for (_, itemNode) in self.visibleItemsWithNodes { + self.applyExternalMediaDimensionsUpdater(to: itemNode) + } + } + } var currentLayout: InstantPageLayout let contentSize: CGSize @@ -223,6 +230,7 @@ public final class InstantPageContentNode : ASDisplayNode { topNode = newNode self.visibleItemsWithNodes[itemIndex] = newNode itemNode = newNode + self.applyExternalMediaDimensionsUpdater(to: newNode) if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.requestLayoutUpdate = { [weak self] animated in @@ -303,6 +311,16 @@ public final class InstantPageContentNode : ASDisplayNode { } } + private func applyExternalMediaDimensionsUpdater(to itemNode: InstantPageNode) { + if let itemNode = itemNode as? InstantPageImageNode { + itemNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } else if let itemNode = itemNode as? InstantPageDetailsNode { + itemNode.contentNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } else if let itemNode = itemNode as? InstantPageSlideshowNode { + itemNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } + } + private func updateWebEmbedHeight(_ index: Int, _ height: CGFloat) { // let currentHeight = self.currentWebEmbedHeights[index] // if height != currentHeight { diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index 2f0445f0b7..241cd9e74e 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -65,6 +65,8 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { var currentWebEmbedHeights: [Int : CGFloat] = [:] var currentExpandedDetails: [Int : Bool]? var currentDetailsItems: [InstantPageDetailsItem] = [] + private var resolvedExternalMediaDimensions: [MediaId: PixelDimensions] = [:] + private var pendingResolvedExternalMediaDimensions = Set() var currentAccessibilityAreas: [AccessibilityAreaNode] = [] @@ -79,6 +81,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { private let loadProgressDisposable = MetaDisposable() private let updateLayoutDisposable = MetaDisposable() + private let updateExternalMediaDimensionsDisposable = MetaDisposable() private var themeReferenceDate: Date? @@ -224,6 +227,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { self.resolveUrlDisposable.dispose() self.loadWebpageDisposable.dispose() self.loadProgressDisposable.dispose() + self.updateExternalMediaDimensionsDisposable.dispose() } func update(settings: InstantPagePresentationSettings, themeSettings: PresentationThemeSettings?, strings: PresentationStrings) { @@ -362,6 +366,8 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { } else { self.webPage = nil } + self.resolvedExternalMediaDimensions.removeAll() + self.pendingResolvedExternalMediaDimensions.removeAll() if let anchor = anchor { self.initialAnchor = anchor.removingPercentEncoding } else if let state = state { @@ -465,17 +471,12 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { } private func updateLayout() { - guard let containerLayout = self.containerLayout, let (webPage, instantPage) = self.webPage, let theme = self.theme else { + guard let containerLayout = self.containerLayout, let (webPage, instantPage) = self.resolvedWebPage(), let theme = self.theme else { return } let currentLayout = instantPageLayoutForWebPage(webPage, instantPage: instantPage, userLocation: self.sourceLocation.userLocation, boundingWidth: containerLayout.size.width, safeInset: containerLayout.safeInsets.left, strings: self.strings, theme: theme, dateTimeFormat: self.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights) - for (_, tileNode) in self.visibleTiles { - tileNode.removeFromSupernode() - } - self.visibleTiles.removeAll() - let currentLayoutTiles = instantPageTilesFromLayout(currentLayout, boundingWidth: containerLayout.size.width) var currentDetailsItems: [InstantPageDetailsItem] = [] @@ -665,6 +666,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { topNode = newNode self.visibleItemsWithNodes[itemIndex] = newNode itemNode = newNode + self.configureExternalMediaDimensionsUpdates(for: newNode) if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.requestLayoutUpdate = { [weak self] animated in @@ -688,6 +690,10 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { } } + if let itemNode = itemNode { + self.configureExternalMediaDimensionsUpdates(for: itemNode) + } + if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.updateVisibleItems(visibleBounds: visibleBounds.offsetBy(dx: -itemNode.frame.minX, dy: -itemNode.frame.minY), animated: animated) } @@ -718,8 +724,11 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { topNode = tileNode self.visibleTiles[tileIndex] = tileNode } else { - if visibleTiles[tileIndex]!.frame != tileFrame { - transition.updateFrame(node: self.visibleTiles[tileIndex]!, frame: tileFrame) + if let tileNode = self.visibleTiles[tileIndex] { + tileNode.update(tile: tile, backgroundColor: theme.pageBackgroundColor) + if tileNode.frame != tileFrame { + transition.updateFrame(node: tileNode, frame: tileFrame) + } } } } @@ -1020,6 +1029,388 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate { return nil } + private func configureExternalMediaDimensionsUpdates(for itemNode: InstantPageNode) { + let update: (MediaId, PixelDimensions) -> Void = { [weak self] mediaId, dimensions in + self?.updateExternalMediaDimensions(mediaId, dimensions) + } + if let itemNode = itemNode as? InstantPageExternalMediaDimensionsNode { + itemNode.updateExternalMediaDimensions = update + } + if let itemNode = itemNode as? InstantPageDetailsNode { + itemNode.contentNode.updateExternalMediaDimensions = update + } + } + + private func updateExternalMediaDimensions(_ mediaId: MediaId, _ dimensions: PixelDimensions) { + if self.resolvedExternalMediaDimensions[mediaId] == dimensions { + return + } + self.resolvedExternalMediaDimensions[mediaId] = dimensions + self.pendingResolvedExternalMediaDimensions.insert(mediaId) + + let signal: Signal = (.complete() |> delay(0.08, queue: Queue.mainQueue())) + self.updateExternalMediaDimensionsDisposable.set(signal.start(completed: { [weak self] in + self?.relayoutForResolvedExternalMediaDimensions() + })) + } + + private func relayoutForResolvedExternalMediaDimensions() { + guard !self.pendingResolvedExternalMediaDimensions.isEmpty else { + return + } + + let mediaIds = Array(self.pendingResolvedExternalMediaDimensions) + self.pendingResolvedExternalMediaDimensions.removeAll() + + let detailsStateMaps = self.captureExpandedDetailsStateMaps() + let viewportTop = self.scrollNode.view.contentOffset.y + self.scrollNode.view.contentInset.top + var oldFrames: [MediaId: CGRect] = [:] + for mediaId in mediaIds { + if let frame = self.effectiveFrameForMedia(mediaId, detailsStateMaps: detailsStateMaps) { + oldFrames[mediaId] = frame + } + } + + self.updateLayout() + + var newFrames: [MediaId: CGRect] = [:] + for mediaId in mediaIds { + if let frame = self.effectiveFrameForMedia(mediaId, detailsStateMaps: detailsStateMaps) { + newFrames[mediaId] = frame + } + } + + if let compensatedViewportTop = self.compensatedViewportTop(oldFrames: oldFrames, newFrames: newFrames, viewportTop: viewportTop) { + self.setViewportTop(compensatedViewportTop) + } + self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds) + } + + private func setViewportTop(_ viewportTop: CGFloat) { + let scrollView = self.scrollNode.view + let minOffsetY = -scrollView.contentInset.top + let maxOffsetY = max(minOffsetY, scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom) + let contentOffsetY = min(max(viewportTop - scrollView.contentInset.top, minOffsetY), maxOffsetY) + if contentOffsetY.isFinite { + let contentOffset = CGPoint(x: scrollView.contentOffset.x, y: contentOffsetY) + scrollView.contentOffset = contentOffset + self.previousContentOffset = contentOffset + self.updateNavigationBar() + } + } + + private func compensatedViewportTop(oldFrames: [MediaId: CGRect], newFrames: [MediaId: CGRect], viewportTop: CGFloat) -> CGFloat? { + var pairedFrames: [(old: CGRect, new: CGRect)] = [] + for (mediaId, oldFrame) in oldFrames { + if let newFrame = newFrames[mediaId] { + pairedFrames.append((oldFrame, newFrame)) + } + } + if pairedFrames.isEmpty { + return nil + } + + if let intersecting = pairedFrames + .filter({ $0.old.height > 0.0 && $0.new.height > 0.0 && viewportTop > $0.old.minY && viewportTop < $0.old.maxY }) + .max(by: { $0.old.minY < $1.old.minY }) { + let ratio = min(max((viewportTop - intersecting.old.minY) / intersecting.old.height, 0.0), 1.0) + return intersecting.new.minY + ratio * intersecting.new.height + } + + if let above = pairedFrames + .filter({ viewportTop >= $0.old.maxY }) + .max(by: { $0.old.maxY < $1.old.maxY }) { + return viewportTop + (above.new.maxY - above.old.maxY) + } + + return nil + } + + private func captureExpandedDetailsStateMaps() -> [String: [Int: Bool]] { + guard let currentLayout = self.currentLayout else { + return [:] + } + var result: [String: [Int: Bool]] = [:] + self.captureExpandedDetailsStateMaps(items: currentLayout.items, visibleItemsWithNodes: self.visibleItemsWithNodes, path: [], result: &result) + return result + } + + private func captureExpandedDetailsStateMaps(items: [InstantPageItem], visibleItemsWithNodes: [Int: InstantPageNode], path: [Int], result: inout [String: [Int: Bool]]) { + let detailsNodes = visibleItemsWithNodes.compactMap { $0.value as? InstantPageDetailsNode } + + var detailsIndex = -1 + for item in items { + guard let detailsItem = item as? InstantPageDetailsItem else { + continue + } + detailsIndex += 1 + + guard let detailsNode = detailsNodes.first(where: { $0.item === detailsItem }) else { + continue + } + let nextPath = path + [detailsIndex] + result[self.detailsStateKey(nextPath)] = detailsNode.contentNode.currentExpandedDetails ?? [:] + self.captureExpandedDetailsStateMaps(items: detailsItem.items, visibleItemsWithNodes: detailsNode.contentNode.visibleItemsWithNodes, path: nextPath, result: &result) + } + } + + private func detailsStateKey(_ path: [Int]) -> String { + if path.isEmpty { + return "" + } + return path.map(String.init).joined(separator: ".") + } + + private func effectiveFrameForMedia(_ mediaId: MediaId, detailsStateMaps: [String: [Int: Bool]]) -> CGRect? { + guard let currentLayout = self.currentLayout else { + return nil + } + return self.effectiveFrameForMedia(mediaId, items: currentLayout.items, origin: .zero, expandedDetails: self.currentExpandedDetails, path: [], detailsStateMaps: detailsStateMaps) + } + + private func effectiveFrameForMedia(_ mediaId: MediaId, items: [InstantPageItem], origin: CGPoint, expandedDetails: [Int: Bool]?, path: [Int], detailsStateMaps: [String: [Int: Bool]]) -> CGRect? { + var collapseOffset: CGFloat = 0.0 + var detailsIndex = -1 + + for item in items { + if item is InstantPageDetailsItem { + detailsIndex += 1 + } + + var itemFrame = item.frame.offsetBy(dx: origin.x, dy: origin.y - collapseOffset) + if let detailsItem = item as? InstantPageDetailsItem { + let nextPath = path + [detailsIndex] + let nestedExpandedDetails = detailsStateMaps[self.detailsStateKey(nextPath)] + let expanded = expandedDetails?[detailsIndex] ?? detailsItem.initiallyExpanded + let height = expanded ? detailsItem.titleHeight + self.effectiveContentHeight(items: detailsItem.items, baseHeight: detailsItem.frame.height - detailsItem.titleHeight, expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) : detailsItem.titleHeight + collapseOffset += item.frame.height - height + itemFrame.size.height = height + + if expanded, let nestedFrame = self.effectiveFrameForMedia(mediaId, items: detailsItem.items, origin: CGPoint(x: itemFrame.minX, y: itemFrame.minY + detailsItem.titleHeight), expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) { + return nestedFrame + } + continue + } + + if self.itemContainsMedia(item, mediaId: mediaId) { + return itemFrame + } + } + + return nil + } + + private func effectiveContentHeight(items: [InstantPageItem], baseHeight: CGFloat, expandedDetails: [Int: Bool]?, path: [Int], detailsStateMaps: [String: [Int: Bool]]) -> CGFloat { + var contentHeight = baseHeight + var detailsIndex = -1 + + for item in items { + guard let detailsItem = item as? InstantPageDetailsItem else { + continue + } + detailsIndex += 1 + + let nextPath = path + [detailsIndex] + let nestedExpandedDetails = detailsStateMaps[self.detailsStateKey(nextPath)] + let expanded = expandedDetails?[detailsIndex] ?? detailsItem.initiallyExpanded + let height = expanded ? detailsItem.titleHeight + self.effectiveContentHeight(items: detailsItem.items, baseHeight: detailsItem.frame.height - detailsItem.titleHeight, expandedDetails: nestedExpandedDetails, path: nextPath, detailsStateMaps: detailsStateMaps) : detailsItem.titleHeight + contentHeight += -detailsItem.frame.height + height + } + + return contentHeight + } + + private func itemContainsMedia(_ item: InstantPageItem, mediaId: MediaId) -> Bool { + for media in item.medias { + if media.media.id == mediaId { + return true + } + } + return false + } + + private func resolvedWebPage() -> (webPage: TelegramMediaWebpage, instantPage: InstantPage?)? { + guard let (webPage, instantPage) = self.webPage else { + return nil + } + guard !self.resolvedExternalMediaDimensions.isEmpty, case let .Loaded(content) = webPage.content else { + return (webPage, instantPage) + } + + var instantPageUpdated = false + var effectiveInstantPage = instantPage + if let instantPage { + var media = instantPage.media + for (mediaId, currentMedia) in instantPage.media { + if let updatedMedia = self.updatedMediaIfNeeded(currentMedia) { + media[mediaId] = updatedMedia + instantPageUpdated = true + } + } + if instantPageUpdated { + effectiveInstantPage = InstantPage(blocks: instantPage.blocks, media: media, isComplete: instantPage.isComplete, rtl: instantPage.rtl, url: instantPage.url, views: instantPage.views) + } + } + + var imageUpdated = false + let effectiveImage = content.image.map { image -> TelegramMediaImage in + if let updated = self.updatedImageIfNeeded(image) { + imageUpdated = true + return updated + } else { + return image + } + } + + var fileUpdated = false + let effectiveFile = content.file.map { file -> TelegramMediaFile in + if let updated = self.updatedFileIfNeeded(file) { + fileUpdated = true + return updated + } else { + return file + } + } + + if !instantPageUpdated && !imageUpdated && !fileUpdated { + return (webPage, instantPage) + } + + let effectiveContent = TelegramMediaWebpageLoadedContent( + url: content.url, + displayUrl: content.displayUrl, + hash: content.hash, + type: content.type, + websiteName: content.websiteName, + title: content.title, + text: content.text, + embedUrl: content.embedUrl, + embedType: content.embedType, + embedSize: content.embedSize, + duration: content.duration, + author: content.author, + isMediaLargeByDefault: content.isMediaLargeByDefault, + imageIsVideoCover: content.imageIsVideoCover, + image: effectiveImage, + file: effectiveFile, + story: content.story, + attributes: content.attributes, + instantPage: effectiveInstantPage + ) + return (TelegramMediaWebpage(webpageId: webPage.webpageId, content: .Loaded(effectiveContent)), effectiveInstantPage) + } + + private func updatedMediaIfNeeded(_ media: Media) -> Media? { + if let image = media as? TelegramMediaImage { + return self.updatedImageIfNeeded(image) + } else if let file = media as? TelegramMediaFile { + return self.updatedFileIfNeeded(file) + } else { + return nil + } + } + + private func updatedImageIfNeeded(_ image: TelegramMediaImage) -> TelegramMediaImage? { + guard let dimensions = self.resolvedExternalMediaDimensions[image.imageId] else { + return nil + } + + var updatedRepresentations = image.representations + var didUpdate = false + for i in 0 ..< updatedRepresentations.count { + let representation = updatedRepresentations[i] + guard representation.resource is InstantPageExternalMediaResource, representation.dimensions != dimensions else { + continue + } + updatedRepresentations[i] = TelegramMediaImageRepresentation( + dimensions: dimensions, + resource: representation.resource, + progressiveSizes: representation.progressiveSizes, + immediateThumbnailData: representation.immediateThumbnailData, + hasVideo: representation.hasVideo, + isPersonal: representation.isPersonal, + typeHint: representation.typeHint + ) + didUpdate = true + } + + guard didUpdate else { + return nil + } + return TelegramMediaImage( + imageId: image.imageId, + representations: updatedRepresentations, + videoRepresentations: image.videoRepresentations, + immediateThumbnailData: image.immediateThumbnailData, + emojiMarkup: image.emojiMarkup, + reference: image.reference, + partialReference: image.partialReference, + flags: image.flags, + video: image.video + ) + } + + private func updatedFileIfNeeded(_ file: TelegramMediaFile) -> TelegramMediaFile? { + guard let dimensions = self.resolvedExternalMediaDimensions[file.fileId], file.resource is InstantPageExternalMediaResource else { + return nil + } + + let (attributes, didUpdate) = self.fileAttributesWithResolvedDimensions(file.attributes, dimensions: dimensions) + guard didUpdate else { + return nil + } + + return TelegramMediaFile( + fileId: file.fileId, + partialReference: file.partialReference, + resource: file.resource, + previewRepresentations: file.previewRepresentations, + videoThumbnails: file.videoThumbnails, + videoCover: file.videoCover, + immediateThumbnailData: file.immediateThumbnailData, + mimeType: file.mimeType, + size: file.size, + attributes: attributes, + alternativeRepresentations: file.alternativeRepresentations + ) + } + + private func fileAttributesWithResolvedDimensions(_ attributes: [TelegramMediaFileAttribute], dimensions: PixelDimensions) -> ([TelegramMediaFileAttribute], Bool) { + var updatedAttributes: [TelegramMediaFileAttribute] = [] + var didUpdate = false + var hasSizeAttribute = false + + for attribute in attributes { + switch attribute { + case let .ImageSize(size): + hasSizeAttribute = true + if size != dimensions { + updatedAttributes.append(.ImageSize(size: dimensions)) + didUpdate = true + } else { + updatedAttributes.append(attribute) + } + case let .Video(duration, size, flags, preloadSize, coverTime, videoCodec): + hasSizeAttribute = true + if size != dimensions { + updatedAttributes.append(.Video(duration: duration, size: dimensions, flags: flags, preloadSize: preloadSize, coverTime: coverTime, videoCodec: videoCodec)) + didUpdate = true + } else { + updatedAttributes.append(attribute) + } + default: + updatedAttributes.append(attribute) + } + } + + if !hasSizeAttribute { + updatedAttributes.append(.ImageSize(size: dimensions)) + didUpdate = true + } + + return (updatedAttributes, didUpdate) + } + private func longPressMedia(_ media: InstantPageMedia) { let controller = makeContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: { [weak self] in if let strongSelf = self, case let .image(image) = media.media { diff --git a/submodules/InstantPageUI/Sources/InstantPageImageItem.swift b/submodules/InstantPageUI/Sources/InstantPageImageItem.swift index e29fcab2d7..c2e49314be 100644 --- a/submodules/InstantPageUI/Sources/InstantPageImageItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageImageItem.swift @@ -54,7 +54,7 @@ public final class InstantPageImageItem: InstantPageItem { public func matchesNode(_ node: InstantPageNode) -> Bool { if let node = node as? InstantPageImageNode { - return node.media == self.media + return instantPageMediaMatchesNodeIdentity(node.media, self.media) } else { return false } diff --git a/submodules/InstantPageUI/Sources/InstantPageImageNode.swift b/submodules/InstantPageUI/Sources/InstantPageImageNode.swift index 76fc85e0fc..63fc534f52 100644 --- a/submodules/InstantPageUI/Sources/InstantPageImageNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageImageNode.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import ImageIO import AsyncDisplayKit import Display import TelegramCore @@ -21,7 +22,35 @@ private struct FetchControls { let cancel: () -> Void } -final class InstantPageImageNode: ASDisplayNode, InstantPageNode { +private enum ExternalImageLoadState { + case loading + case ready + case failed +} + +private func externalImagePixelDimensions(data: Data) -> PixelDimensions? { + guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { + return nil + } + guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any] else { + return nil + } + guard let pixelWidth = (properties[kCGImagePropertyPixelWidth] as? NSNumber)?.int32Value, + let pixelHeight = (properties[kCGImagePropertyPixelHeight] as? NSNumber)?.int32Value, + pixelWidth > 0, pixelHeight > 0 else { + return nil + } + + let orientation = imageOrientationFromSource(source) + switch orientation { + case .left, .right, .leftMirrored, .rightMirrored: + return PixelDimensions(width: pixelHeight, height: pixelWidth) + default: + return PixelDimensions(width: pixelWidth, height: pixelHeight) + } +} + +final class InstantPageImageNode: ASDisplayNode, InstantPageNode, InstantPageExternalMediaDimensionsNode { private let context: AccountContext private let webPage: TelegramMediaWebpage private var theme: InstantPageTheme @@ -32,8 +61,13 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { private let fit: Bool private let openMedia: (InstantPageMedia) -> Void private let longPressMedia: (InstantPageMedia) -> Void + private let getPreloadedResource: (String) -> Data? private var fetchControls: FetchControls? + private var externalImageLoadState: ExternalImageLoadState? + var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? + private var externalMediaDimensions: PixelDimensions? + private var didReportExternalMediaDimensions = false private let pinchContainerNode: PinchSourceContainerNode private let imageNode: TransformImageNode @@ -48,6 +82,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { private var statusDisposable = MetaDisposable() private var themeUpdated: Bool = false + private var externalMediaDimensionsUpdated: Bool = false init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute], interactive: Bool, roundCorners: Bool, fit: Bool, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, getPreloadedResource: @escaping (String) -> Data?) { self.context = context @@ -60,6 +95,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { self.fit = fit self.openMedia = openMedia self.longPressMedia = longPressMedia + self.getPreloadedResource = getPreloadedResource self.pinchContainerNode = PinchSourceContainerNode() self.imageNode = TransformImageNode() @@ -72,33 +108,14 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { self.pinchContainerNode.contentNode.addSubnode(self.imageNode) self.addSubnode(self.pinchContainerNode) + if interactive, media.url != nil { + self.linkIconNode.image = UIImage(bundleImageName: "Instant View/ImageLink") + self.pinchContainerNode.contentNode.addSubnode(self.linkIconNode) + } + if case let .image(image) = media.media, let largest = largestImageRepresentation(image.representations) { if let externalResource = largest.resource as? InstantPageExternalMediaResource { - var url = externalResource.url - if !url.hasPrefix("http") && !url.hasPrefix("https") && url.hasPrefix("//") { - url = "https:\(url)" - } - let photoData: Signal, NoError> - if let preloadedData = getPreloadedResource(externalResource.url) { - photoData = .single(Tuple4(nil, preloadedData, .full, true)) - } else { - photoData = context.engine.resources.httpData(url: url, preserveExactUrl: true) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> map { data in - if let data { - return Tuple4(nil, data, .full, true) - } else { - return Tuple4(nil, nil, .full, false) - } - } - } - self.imageNode.setSignal(chatMessagePhotoInternal(photoData: photoData) - |> map { _, _, generate in - return generate - }) + self.loadExternalImage(resourceUrl: externalResource.url) } else { let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image) self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference)) @@ -124,38 +141,13 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { } } })) - - if media.url != nil { - self.linkIconNode.image = UIImage(bundleImageName: "Instant View/ImageLink") - self.pinchContainerNode.contentNode.addSubnode(self.linkIconNode) - } - + self.pinchContainerNode.contentNode.addSubnode(self.statusNode) } } } else if case let .file(file) = media.media { if let externalResource = file.resource as? InstantPageExternalMediaResource { - let photoData: Signal, NoError> - if let preloadedData = getPreloadedResource(externalResource.url) { - photoData = .single(Tuple4(nil, preloadedData, .full, true)) - } else { - photoData = context.engine.resources.httpData(url: externalResource.url, preserveExactUrl: true) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> map { data in - if let data { - return Tuple4(nil, data, .full, true) - } else { - return Tuple4(nil, nil, .full, false) - } - } - } - self.imageNode.setSignal(chatMessagePhotoInternal(photoData: photoData) - |> map { _, _, generate in - return generate - }) + self.loadExternalImage(resourceUrl: externalResource.url) } else { let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file) if file.mimeType.hasPrefix("image/") { @@ -235,6 +227,114 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { } } + private func loadExternalImage(resourceUrl: String) { + self.externalImageLoadState = .loading + self.updateExternalImageLoadState() + + var requestUrl = resourceUrl + if !requestUrl.hasPrefix("http") && !requestUrl.hasPrefix("https") && requestUrl.hasPrefix("//") { + requestUrl = "https:\(requestUrl)" + } + + let photoData: Signal, NoError> + if let preloadedData = self.getPreloadedResource(resourceUrl) { + photoData = .single(Tuple4(nil, preloadedData, .full, true)) + } else { + photoData = self.context.engine.resources.httpData(url: requestUrl, preserveExactUrl: true) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { data in + if let data { + return Tuple4(nil, data, .full, true) + } else { + return Tuple4(nil, nil, .full, false) + } + } + } + + let stateAwarePhotoData = photoData + |> deliverOnMainQueue + |> afterNext { [weak self] value in + guard let strongSelf = self else { + return + } + if let data = value._1 ?? value._0, UIImage(data: data) != nil { + if let dimensions = externalImagePixelDimensions(data: data) { + strongSelf.externalMediaDimensions = dimensions + strongSelf.externalMediaDimensionsUpdated = true + strongSelf.maybeUpdateExternalMediaDimensions(dimensions) + } + strongSelf.externalImageLoadState = .ready + strongSelf.setNeedsLayout() + } else { + strongSelf.externalImageLoadState = .failed + } + strongSelf.updateExternalImageLoadState() + } + + self.imageNode.setSignal(chatMessagePhotoInternal(photoData: stateAwarePhotoData) + |> map { _, _, generate in + return generate + }) + + self.fetchControls = FetchControls(fetch: { [weak self] _ in + self?.loadExternalImage(resourceUrl: resourceUrl) + }, cancel: {}) + } + + private func currentMediaDimensions() -> PixelDimensions? { + if case let .image(image) = self.media.media, let largest = largestImageRepresentation(image.representations) { + return largest.dimensions + } else if case let .file(file) = self.media.media { + return file.dimensions + } else { + return nil + } + } + + private func effectiveMediaDimensions() -> PixelDimensions? { + return self.externalMediaDimensions ?? self.currentMediaDimensions() + } + + private func maybeUpdateExternalMediaDimensions(_ dimensions: PixelDimensions) { + guard !self.didReportExternalMediaDimensions, let mediaId = self.media.media.id else { + return + } + if let currentDimensions = self.currentMediaDimensions(), currentDimensions == dimensions { + return + } + self.didReportExternalMediaDimensions = true + self.updateExternalMediaDimensions?(mediaId, dimensions) + } + + private func updateExternalImageLoadState() { + guard let externalImageLoadState = self.externalImageLoadState else { + return + } + + if self.statusNode.supernode == nil { + self.pinchContainerNode.contentNode.addSubnode(self.statusNode) + } + + let state: RadialStatusNodeState + switch externalImageLoadState { + case .loading: + state = .progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true) + case .ready: + state = .none + case .failed: + state = .none + } + + self.statusNode.transitionToState(state, completion: { [weak statusNode] in + if state == .none { + statusNode?.removeFromSupernode() + } + }) + } + private func updateFetchStatus() { var state: RadialStatusNodeState = .none if let fetchStatus = self.fetchStatus { @@ -260,19 +360,20 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { let size = self.bounds.size - if self.currentSize != size || self.themeUpdated { + if self.currentSize != size || self.themeUpdated || self.externalMediaDimensionsUpdated { self.currentSize = size self.themeUpdated = false + self.externalMediaDimensionsUpdated = false self.pinchContainerNode.frame = CGRect(origin: CGPoint(), size: size) self.pinchContainerNode.update(size: size, transition: .immediate) self.imageNode.frame = CGRect(origin: CGPoint(), size: size) - let radialStatusSize: CGFloat = 50.0 + let radialStatusSize: CGFloat = max(18.0, min(50.0, floor(min(size.width, size.height) * 0.7))) self.statusNode.frame = CGRect(x: floorToScreenPixels((size.width - radialStatusSize) / 2.0), y: floorToScreenPixels((size.height - radialStatusSize) / 2.0), width: radialStatusSize, height: radialStatusSize) - if case let .image(image) = self.media.media, let largest = largestImageRepresentation(image.representations) { - let imageSize = largest.dimensions.cgSize.aspectFilled(size) + if case .image = self.media.media, let dimensions = self.effectiveMediaDimensions() { + let imageSize = dimensions.cgSize.aspectFilled(size) let boundingSize = size let radius: CGFloat = self.roundCorners ? floor(min(imageSize.width, imageSize.height) / 2.0) : 0.0 let makeLayout = self.imageNode.asyncLayout() @@ -280,7 +381,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { apply() self.linkIconNode.frame = CGRect(x: size.width - 38.0, y: 14.0, width: 24.0, height: 24.0) - } else if case let .file(file) = self.media.media, let dimensions = file.dimensions { + } else if case let .file(file) = self.media.media, let dimensions = self.effectiveMediaDimensions() { let emptyColor = file.mimeType.hasPrefix("image/") ? self.theme.imageTintColor : nil let imageSize = dimensions.cgSize.aspectFilled(size) @@ -318,7 +419,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { } func transitionNode(media: InstantPageMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { - if media == self.media { + if instantPageMediaMatchesNodeIdentity(media, self.media) { let imageNode = self.imageNode return (self.imageNode, self.imageNode.bounds, { [weak imageNode] in return (imageNode?.view.snapshotContentTree(unhide: true), nil) @@ -329,14 +430,32 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode { } func updateHiddenMedia(media: InstantPageMedia?) { - self.imageNode.isHidden = self.media == media + if let media { + self.imageNode.isHidden = instantPageMediaMatchesNodeIdentity(self.media, media) + } else { + self.imageNode.isHidden = false + } self.statusNode.isHidden = self.imageNode.isHidden + self.linkIconNode.isHidden = self.imageNode.isHidden } @objc private func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { switch recognizer.state { case .ended: if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation { + if let externalImageLoadState = self.externalImageLoadState { + switch externalImageLoadState { + case .loading: + return + case .failed: + if case .tap = gesture { + self.fetchControls?.fetch(true) + } + return + case .ready: + break + } + } if let fetchStatus = self.fetchStatus { switch fetchStatus { case .Local: diff --git a/submodules/InstantPageUI/Sources/InstantPageMedia.swift b/submodules/InstantPageUI/Sources/InstantPageMedia.swift index ff9b2bc3f5..a7813f63bd 100644 --- a/submodules/InstantPageUI/Sources/InstantPageMedia.swift +++ b/submodules/InstantPageUI/Sources/InstantPageMedia.swift @@ -20,3 +20,28 @@ public struct InstantPageMedia: Equatable { return lhs.index == rhs.index && lhs.media == rhs.media && lhs.url == rhs.url && lhs.caption == rhs.caption && lhs.credit == rhs.credit } } + +func instantPageMediaMatchesNodeIdentity(_ lhs: InstantPageMedia, _ rhs: InstantPageMedia) -> Bool { + if lhs.index != rhs.index { + return false + } + if lhs.url != rhs.url || lhs.caption != rhs.caption || lhs.credit != rhs.credit { + return false + } + if let lhsId = lhs.media.id, let rhsId = rhs.media.id { + return lhsId == rhsId + } + return lhs == rhs +} + +func instantPageMediaArraysMatchNodeIdentity(_ lhs: [InstantPageMedia], _ rhs: [InstantPageMedia]) -> Bool { + if lhs.count != rhs.count { + return false + } + for i in 0 ..< lhs.count { + if !instantPageMediaMatchesNodeIdentity(lhs[i], rhs[i]) { + return false + } + } + return true +} diff --git a/submodules/InstantPageUI/Sources/InstantPageNode.swift b/submodules/InstantPageUI/Sources/InstantPageNode.swift index c235614961..fb011c454f 100644 --- a/submodules/InstantPageUI/Sources/InstantPageNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageNode.swift @@ -2,8 +2,13 @@ import Foundation import UIKit import AsyncDisplayKit import Display +import TelegramCore import TelegramPresentationData +public protocol InstantPageExternalMediaDimensionsNode: AnyObject { + var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? { get set } +} + public protocol InstantPageNode: ASDisplayNode { func updateIsVisible(_ isVisible: Bool) diff --git a/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift b/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift index d9a39cabfc..560185cd86 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift @@ -30,7 +30,7 @@ final class InstantPageSlideshowItem: InstantPageItem { func matchesNode(_ node: InstantPageNode) -> Bool { if let node = node as? InstantPageSlideshowNode { - return self.medias == node.medias + return instantPageMediaArraysMatchNodeIdentity(self.medias, node.medias) } else { return false } @@ -55,4 +55,3 @@ final class InstantPageSlideshowItem: InstantPageItem { func drawInTile(context: CGContext) { } } - diff --git a/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift b/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift index 6baa616027..6fcc36030f 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift @@ -61,6 +61,12 @@ private final class InstantPageSlideshowItemNode: ASDisplayNode { } return nil } + + func updateExternalMediaDimensions(_ update: ((EngineMedia.Id, PixelDimensions) -> Void)?) { + if let node = self.contentNode as? InstantPageImageNode { + node.updateExternalMediaDimensions = update + } + } } private final class InstantPageSlideshowPagerNode: ASDisplayNode, ASScrollViewDelegate { @@ -88,6 +94,13 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, ASScrollViewDe } private var containerLayout: ContainerViewLayout? + var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? { + didSet { + for node in self.itemNodes { + node.updateExternalMediaDimensions(self.updateExternalMediaDimensions) + } + } + } var centralItemIndexUpdated: (Int?) -> Void = { _ in } @@ -195,6 +208,7 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, ASScrollViewDe } let node = InstantPageSlideshowItemNode(contentNode: contentNode) + node.updateExternalMediaDimensions(self.updateExternalMediaDimensions) node.index = index return node @@ -380,8 +394,13 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, ASScrollViewDe } } -final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode { +final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode, InstantPageExternalMediaDimensionsNode { var medias: [InstantPageMedia] = [] + var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? { + didSet { + self.pagerNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } + } private let pagerNode: InstantPageSlideshowPagerNode private let pageControlNode: PageControlNode diff --git a/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift b/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift index 30bdf1c6d9..d3633c7f9b 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift @@ -8,7 +8,7 @@ import TelegramPresentationData import TelegramUIPreferences import AccountContext -final class InstantPageSubContentNode : ASDisplayNode { +final class InstantPageSubContentNode : ASDisplayNode, InstantPageExternalMediaDimensionsNode { private let context: AccountContext private let strings: PresentationStrings private let nameDisplayOrder: PresentationPersonNameOrder @@ -32,6 +32,13 @@ final class InstantPageSubContentNode : ASDisplayNode { var currentDetailsItems: [InstantPageDetailsItem] = [] var requestLayoutUpdate: ((Bool) -> Void)? + var updateExternalMediaDimensions: ((EngineMedia.Id, PixelDimensions) -> Void)? { + didSet { + for (_, itemNode) in self.visibleItemsWithNodes { + self.applyExternalMediaDimensionsUpdater(to: itemNode) + } + } + } var currentLayout: InstantPageLayout let contentSize: CGSize @@ -209,6 +216,7 @@ final class InstantPageSubContentNode : ASDisplayNode { topNode = newNode self.visibleItemsWithNodes[itemIndex] = newNode itemNode = newNode + self.applyExternalMediaDimensionsUpdater(to: newNode) if let itemNode = itemNode as? InstantPageDetailsNode { itemNode.requestLayoutUpdate = { [weak self] animated in @@ -289,6 +297,16 @@ final class InstantPageSubContentNode : ASDisplayNode { } } + private func applyExternalMediaDimensionsUpdater(to itemNode: InstantPageNode) { + if let itemNode = itemNode as? InstantPageImageNode { + itemNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } else if let itemNode = itemNode as? InstantPageDetailsNode { + itemNode.contentNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } else if let itemNode = itemNode as? InstantPageSlideshowNode { + itemNode.updateExternalMediaDimensions = self.updateExternalMediaDimensions + } + } + private func updateWebEmbedHeight(_ index: Int, _ height: CGFloat) { // let currentHeight = self.currentWebEmbedHeights[index] // if height != currentHeight { diff --git a/submodules/InstantPageUI/Sources/InstantPageTileNode.swift b/submodules/InstantPageUI/Sources/InstantPageTileNode.swift index c16bcac1dd..3ed1a30426 100644 --- a/submodules/InstantPageUI/Sources/InstantPageTileNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageTileNode.swift @@ -15,10 +15,12 @@ private final class InstantPageTileNodeParameters: NSObject { } public final class InstantPageTileNode: ASDisplayNode { - private let tile: InstantPageTile + private var tile: InstantPageTile + private var tileBackgroundColor: UIColor public init(tile: InstantPageTile, backgroundColor: UIColor) { self.tile = tile + self.tileBackgroundColor = backgroundColor super.init() @@ -27,8 +29,15 @@ public final class InstantPageTileNode: ASDisplayNode { self.backgroundColor = backgroundColor } + public func update(tile: InstantPageTile, backgroundColor: UIColor) { + self.tile = tile + self.tileBackgroundColor = backgroundColor + self.backgroundColor = backgroundColor + self.setNeedsDisplay() + } + public override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? { - return InstantPageTileNodeParameters(tile: self.tile, backgroundColor: self.backgroundColor ?? UIColor.white) + return InstantPageTileNodeParameters(tile: self.tile, backgroundColor: self.tileBackgroundColor) } @objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) { diff --git a/submodules/LocationUI/BUILD b/submodules/LocationUI/BUILD index 8843a0ed2b..321fd7dd3a 100644 --- a/submodules/LocationUI/BUILD +++ b/submodules/LocationUI/BUILD @@ -48,6 +48,7 @@ swift_library( "//submodules/Components/BundleIconComponent", "//submodules/TelegramUI/Components/GlassBackgroundComponent", "//submodules/TelegramUI/Components/GlassBarButtonComponent", + "//submodules/TelegramUI/Components/GlassControls", "//submodules/TelegramUI/Components/EdgeEffect", "//submodules/TelegramUI/Components/SearchInputPanelComponent", "//submodules/TelegramUI/Components/ButtonComponent", diff --git a/submodules/LocationUI/Sources/LocationInfoListItem.swift b/submodules/LocationUI/Sources/LocationInfoListItem.swift index fda4a00e51..032f1f621c 100644 --- a/submodules/LocationUI/Sources/LocationInfoListItem.swift +++ b/submodules/LocationUI/Sources/LocationInfoListItem.swift @@ -100,7 +100,7 @@ public final class LocationInfoListItemNode: ListViewItemNode { super.init(layerBacked: false, rotated: false, seeThrough: false) - self.addSubnode(self.backgroundNode) + //self.addSubnode(self.backgroundNode) self.addSubnode(self.buttonNode) self.addSubnode(self.venueIconNode) diff --git a/submodules/LocationUI/Sources/LocationMapHeaderNode.swift b/submodules/LocationUI/Sources/LocationMapHeaderNode.swift index 34d88662f9..c3ef2e37d1 100644 --- a/submodules/LocationUI/Sources/LocationMapHeaderNode.swift +++ b/submodules/LocationUI/Sources/LocationMapHeaderNode.swift @@ -57,7 +57,7 @@ public final class LocationMapHeaderNode: ASDisplayNode { private let options: ComponentView? - private let optionsBackgroundView: GlassBackgroundView? + private let optionsBackgroundView: GlassContextExtractableContainer? private let optionsBackgroundNode: ASImageNode private let optionsSeparatorNode: ASDisplayNode private let optionsSecondSeparatorNode: ASDisplayNode @@ -66,7 +66,7 @@ public final class LocationMapHeaderNode: ASDisplayNode { private let notificationButtonNode: HighlightableButtonNode private let placesBackgroundView: GlassBackgroundView? private let placesBackgroundNode: ASImageNode - private let placesButtonNode: HighlightableButtonNode + private let placesButtonNode: HighlightTrackingButtonNode private let shadowNode: ASImageNode private var validLayout: (ContainerViewLayout, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGSize)? @@ -132,7 +132,7 @@ public final class LocationMapHeaderNode: ASDisplayNode { self.placesBackgroundNode.image = generateBackgroundImage(theme: presentationData.theme) self.placesBackgroundNode.isUserInteractionEnabled = true - self.placesButtonNode = HighlightableButtonNode() + self.placesButtonNode = HighlightTrackingButtonNode() self.placesButtonNode.setTitle(presentationData.strings.Map_PlacesInThisArea, with: Font.medium(17.0), with: self.glass ? presentationData.theme.rootController.navigationBar.primaryTextColor : buttonColor, for: .normal) self.shadowNode = ASImageNode() @@ -142,7 +142,7 @@ public final class LocationMapHeaderNode: ASDisplayNode { self.shadowNode.image = generateShadowImage(theme: presentationData.theme, highlighted: false) if glass { - self.optionsBackgroundView = GlassBackgroundView() + self.optionsBackgroundView = GlassContextExtractableContainer() self.optionsBackgroundNode.image = nil self.placesBackgroundView = GlassBackgroundView() @@ -169,16 +169,16 @@ public final class LocationMapHeaderNode: ASDisplayNode { self.view.addSubview(optionsBackgroundView) } self.addSubnode(self.optionsBackgroundNode) - self.optionsBackgroundNode.addSubnode(self.optionsSeparatorNode) - self.optionsBackgroundNode.addSubnode(self.optionsSecondSeparatorNode) - self.optionsBackgroundNode.addSubnode(self.infoButtonNode) - self.optionsBackgroundNode.addSubnode(self.locationButtonNode) - self.optionsBackgroundNode.addSubnode(self.notificationButtonNode) + self.optionsBackgroundView?.contentView.addSubview(self.optionsSeparatorNode.view) + self.optionsBackgroundView?.contentView.addSubview(self.optionsSecondSeparatorNode.view) + self.optionsBackgroundView?.contentView.addSubview(self.infoButtonNode.view) + self.optionsBackgroundView?.contentView.addSubview(self.locationButtonNode.view) + self.optionsBackgroundView?.contentView.addSubview(self.notificationButtonNode.view) } } self.addSubnode(self.placesBackgroundNode) - self.placesBackgroundNode.addSubnode(self.placesButtonNode) + self.placesBackgroundView?.contentView.addSubview(self.placesButtonNode.view) //self.addSubnode(self.shadowNode) self.infoButtonNode.addTarget(self, action: #selector(self.infoPressed), forControlEvents: .touchUpInside) @@ -252,16 +252,16 @@ public final class LocationMapHeaderNode: ASDisplayNode { let inset: CGFloat = 6.0 let placesButtonSize = CGSize(width: 180.0 + panelInset * 2.0, height: 45.0 + panelInset * 2.0) - let placesButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - placesButtonSize.width) / 2.0), y: navigationBarHeight + topPadding - 6.0), size: placesButtonSize) + let placesButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - placesButtonSize.width) / 2.0), y: navigationBarHeight + topPadding - 6.0), size: placesButtonSize).insetBy(dx: 5.0, dy: 6.0) transition.updateFrame(node: self.placesBackgroundNode, frame: placesButtonFrame) if let placesBackgroundView = self.placesBackgroundView { - let backgroundViewFrame = CGRect(origin: .zero, size: placesButtonFrame.size).insetBy(dx: 5.0, dy: 6.0) + let backgroundViewFrame = CGRect(origin: .zero, size: placesButtonFrame.size) transition.updateFrame(view: placesBackgroundView, frame: backgroundViewFrame) - placesBackgroundView.update(size: backgroundViewFrame.size, cornerRadius: backgroundViewFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel), transition: .immediate) + placesBackgroundView.update(size: backgroundViewFrame.size, cornerRadius: backgroundViewFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel), isInteractive: true, transition: .immediate) } - transition.updateFrame(node: self.placesButtonNode, frame: CGRect(origin: CGPoint(), size: placesButtonSize)) + transition.updateFrame(node: self.placesButtonNode, frame: CGRect(origin: CGPoint(), size: placesButtonFrame.size)) transition.updateAlpha(node: self.placesBackgroundNode, alpha: self.displayingPlacesButton ? 1.0 : 0.0) transition.updateAlpha(node: self.placesButtonNode, alpha: self.displayingPlacesButton ? 1.0 : 0.0) @@ -327,7 +327,7 @@ public final class LocationMapHeaderNode: ASDisplayNode { if let optionsBackgroundView = self.optionsBackgroundView { let backgroundViewFrame = backgroundFrame.insetBy(dx: 4.0, dy: 4.0) transition.updateFrame(view: optionsBackgroundView, frame: backgroundViewFrame) - optionsBackgroundView.update(size: backgroundViewFrame.size, cornerRadius: backgroundViewFrame.width * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel), transition: .immediate) + optionsBackgroundView.update(size: backgroundViewFrame.size, cornerRadius: backgroundViewFrame.width * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel), isInteractive: true, transition: .immediate) } let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) diff --git a/submodules/LocationUI/Sources/LocationViewController.swift b/submodules/LocationUI/Sources/LocationViewController.swift index df3b15b229..4faec7447e 100644 --- a/submodules/LocationUI/Sources/LocationViewController.swift +++ b/submodules/LocationUI/Sources/LocationViewController.swift @@ -11,7 +11,6 @@ import AppBundle import CoreLocation import PresentationDataUtils import OpenInExternalAppUI - import DeviceAccess import UndoUI import MapKit @@ -32,12 +31,6 @@ public class LocationViewParams { } } -enum LocationViewRightBarButton { - case none - case share - case showAll -} - class LocationViewInteraction { let toggleMapModeSelection: () -> Void let updateMapMode: (LocationMapMode) -> Void @@ -49,10 +42,9 @@ class LocationViewInteraction { let updateSendActionHighlight: (Bool) -> Void let sendLiveLocation: (Int32?, Bool, EngineMessage.Id?) -> Void let stopLiveLocation: () -> Void - let updateRightBarButton: (LocationViewRightBarButton) -> Void let present: (ViewController) -> Void - init(toggleMapModeSelection: @escaping () -> Void, updateMapMode: @escaping (LocationMapMode) -> Void, toggleTrackingMode: @escaping () -> Void, goToCoordinate: @escaping (CLLocationCoordinate2D) -> Void, requestDirections: @escaping (TelegramMediaMap, String?, OpenInLocationDirections) -> Void, share: @escaping () -> Void, setupProximityNotification: @escaping (Bool, EngineMessage.Id?) -> Void, updateSendActionHighlight: @escaping (Bool) -> Void, sendLiveLocation: @escaping (Int32?, Bool, EngineMessage.Id?) -> Void, stopLiveLocation: @escaping () -> Void, updateRightBarButton: @escaping (LocationViewRightBarButton) -> Void, present: @escaping (ViewController) -> Void) { + init(toggleMapModeSelection: @escaping () -> Void, updateMapMode: @escaping (LocationMapMode) -> Void, toggleTrackingMode: @escaping () -> Void, goToCoordinate: @escaping (CLLocationCoordinate2D) -> Void, requestDirections: @escaping (TelegramMediaMap, String?, OpenInLocationDirections) -> Void, share: @escaping () -> Void, setupProximityNotification: @escaping (Bool, EngineMessage.Id?) -> Void, updateSendActionHighlight: @escaping (Bool) -> Void, sendLiveLocation: @escaping (Int32?, Bool, EngineMessage.Id?) -> Void, stopLiveLocation: @escaping () -> Void, present: @escaping (ViewController) -> Void) { self.toggleMapModeSelection = toggleMapModeSelection self.updateMapMode = updateMapMode self.toggleTrackingMode = toggleTrackingMode @@ -63,7 +55,6 @@ class LocationViewInteraction { self.updateSendActionHighlight = updateSendActionHighlight self.sendLiveLocation = sendLiveLocation self.stopLiveLocation = stopLiveLocation - self.updateRightBarButton = updateRightBarButton self.present = present } } @@ -83,9 +74,7 @@ public final class LocationViewController: ViewController { private let locationManager = LocationManager() private var interaction: LocationViewInteraction? - - private var rightBarButtonAction: LocationViewRightBarButton = .none - + public var dismissed: () -> Void = {} public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, subject: EngineMessage, isStoryLocation: Bool = false, isPreview: Bool = false, params: LocationViewParams) { @@ -97,33 +86,19 @@ public final class LocationViewController: ViewController { self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } - let navigationBarPresentationData: NavigationBarPresentationData? - if !isPreview { - navigationBarPresentationData = NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(.clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)) - } else { - navigationBarPresentationData = nil - } + super.init(navigationBarPresentationData: nil) - super.init(navigationBarPresentationData: navigationBarPresentationData) + self._hasGlassStyle = true self.navigationPresentation = .modal - - if !self.isPreview { - self.title = self.presentationData.strings.Map_LocationTitle - self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed)) - } - + self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData) |> deliverOnMainQueue).start(next: { [weak self] presentationData in guard let strongSelf = self, strongSelf.presentationData.theme !== presentationData.theme else { return } strongSelf.presentationData = presentationData - - strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: strongSelf.presentationData.theme).withUpdatedSeparatorColor(.clear), strings: NavigationBarStrings(presentationStrings: strongSelf.presentationData.strings)), transition: .immediate) - - strongSelf.updateRightBarButton() - + if strongSelf.isNodeLoaded { strongSelf.controllerNode.updatePresentationData(presentationData) } @@ -466,15 +441,6 @@ public final class LocationViewController: ViewController { }, stopLiveLocation: { [weak self] in params.stopLiveLocation(nil) self?.dismiss() - }, updateRightBarButton: { [weak self] action in - guard let strongSelf = self else { - return - } - - if action != strongSelf.rightBarButtonAction { - strongSelf.rightBarButtonAction = action - strongSelf.updateRightBarButton() - } }, present: { [weak self] c in if let strongSelf = self { strongSelf.present(c, in: .window(.root)) @@ -515,7 +481,7 @@ public final class LocationViewController: ViewController { return } - self.displayNode = LocationViewControllerNode(context: self.context, presentationData: self.presentationData, subject: self.subject, interaction: interaction, locationManager: self.locationManager, isStoryLocation: self.isStoryLocation, isPreview: self.isPreview) + self.displayNode = LocationViewControllerNode(context: self.context, controller: self, presentationData: self.presentationData, subject: self.subject, interaction: interaction, locationManager: self.locationManager, isStoryLocation: self.isStoryLocation, isPreview: self.isPreview) self.displayNodeDidLoad() self.controllerNode.onAnnotationsReady = { [weak self] in @@ -528,39 +494,12 @@ public final class LocationViewController: ViewController { self.controllerNode.headerNode.mapNode.disableHorizontalTransitionGesture = self.isStoryLocation } - private func updateRightBarButton() { - guard !self.isPreview else { - return - } - switch self.rightBarButtonAction { - case .none: - self.navigationItem.rightBarButtonItem = nil - case .share: - self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationShareIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.sharePressed)) - self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.VoiceOver_MessageContextShare - case .showAll: - self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Map_LiveLocationShowAll, style: .plain, target: self, action: #selector(self.showAllPressed)) - } - } - override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) self.controllerNode.containerLayoutUpdated(layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) } - - @objc private func cancelPressed() { - self.dismiss() - } - - @objc private func sharePressed() { - self.interaction?.share() - } - - @objc private func showAllPressed() { - self.controllerNode.showAll() - } - + private var didDismiss = false public override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 2dedaed1a4..b2907103ef 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -17,6 +17,11 @@ import CoreLocation import Geocoding import DeviceAccess import TooltipUI +import ComponentFlow +import GlassControls +import BundleIconComponent +import EdgeEffect +import MultilineTextComponent func getLocation(from message: EngineMessage) -> TelegramMediaMap? { if let poll = message.media.first(where: { $0 is TelegramMediaPoll } ) as? TelegramMediaPoll, let map = poll.attachedMedia as? TelegramMediaMap { @@ -212,6 +217,12 @@ private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntr return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates, gotTravelTimes: gotTravelTimes, count: toEntries.count, animated: animated) } +enum LocationViewRightBarButton { + case none + case share + case showAll +} + public enum LocationViewLocation: Equatable { case initial case user @@ -268,6 +279,7 @@ public struct LocationViewState { final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationManagerDelegate { private let context: AccountContext + private weak var controller: LocationViewController? private var presentationData: PresentationData private let presentationDataPromise: Promise private var subject: EngineMessage @@ -276,9 +288,14 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan private let isStoryLocation: Bool private let isPreview: Bool + private var rightBarButtonAction: LocationViewRightBarButton = .none + + private let topEdgeEffectView = EdgeEffectView() + private let buttons = ComponentView() + private let title = ComponentView() + private let listNode: ListView let headerNode: LocationMapHeaderNode - private let optionsNode: LocationOptionsNode private var enqueuedTransitions: [LocationViewTransaction] = [] @@ -302,8 +319,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } private let travelTimesPromise = Promise<[EngineMessage.Id: (Double, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime)]>([:]) - init(context: AccountContext, presentationData: PresentationData, subject: EngineMessage, interaction: LocationViewInteraction, locationManager: LocationManager, isStoryLocation: Bool, isPreview: Bool) { + init(context: AccountContext, controller: LocationViewController, presentationData: PresentationData, subject: EngineMessage, interaction: LocationViewInteraction, locationManager: LocationManager, isStoryLocation: Bool, isPreview: Bool) { self.context = context + self.controller = controller self.presentationData = presentationData self.presentationDataPromise = Promise(presentationData) self.subject = subject @@ -316,7 +334,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan self.statePromise = Promise(self.state) self.listNode = ListViewImpl() - self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor + self.listNode.backgroundColor = .clear //self.presentationData.theme.list.plainBackgroundColor self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3) self.listNode.verticalScrollIndicatorFollowsOverscroll = true self.listNode.accessibilityPageScrolledString = { row, count in @@ -326,29 +344,24 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan var setupProximityNotificationImpl: ((Bool) -> Void)? self.headerNode = LocationMapHeaderNode( presentationData: presentationData, - glass: false, - isPreview: true, + glass: true, + isPreview: self.isPreview, toggleMapModeSelection: interaction.toggleMapModeSelection, updateMapMode: interaction.updateMapMode, goToUserLocation: interaction.toggleTrackingMode, setupProximityNotification: { reset in - setupProximityNotificationImpl?(reset) - }) - //self.headerNode.mapNode.isRotateEnabled = false - - self.optionsNode = LocationOptionsNode(presentationData: presentationData, updateMapMode: interaction.updateMapMode) - + setupProximityNotificationImpl?(reset) + } + ) + super.init() - self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor + self.backgroundColor = .red // self.presentationData.theme.list.plainBackgroundColor if !self.isPreview { self.addSubnode(self.listNode) } self.addSubnode(self.headerNode) - if !self.isPreview { - self.addSubnode(self.optionsNode) - } let userLocation: Signal = .single(nil) |> then( @@ -707,7 +720,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } else { rightBarButtonAction = .share } - strongSelf.interaction.updateRightBarButton(rightBarButtonAction) + strongSelf.rightBarButtonAction = rightBarButtonAction if let (layout, navigationBarHeight) = strongSelf.validLayout { var updateLayout = false @@ -800,10 +813,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan self.presentationData = presentationData self.presentationDataPromise.set(.single(presentationData)) - self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor - self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor + self.backgroundColor = .red //self.presentationData.theme.list.plainBackgroundColor + self.listNode.backgroundColor = .clear // self.presentationData.theme.list.plainBackgroundColor self.headerNode.updatePresentationData(self.presentationData) - self.optionsNode.updatePresentationData(self.presentationData) } func updateState(_ f: (LocationViewState) -> LocationViewState) { @@ -970,10 +982,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } else { headerHeight = topInset + overlap } - let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: headerHeight)) + let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)) transition.updateFrame(node: self.headerNode, frame: headerFrame) - self.headerNode.updateLayout(layout: layout, navigationBarHeight: navigationHeight, topPadding: self.state.displayingMapModeOptions ? optionsHeight : 0.0, controlsTopPadding: self.state.displayingMapModeOptions ? optionsHeight : 0.0, controlsBottomPadding: 0.0, offset: 0.0, size: headerFrame.size, transition: transition) + self.headerNode.updateLayout(layout: layout, navigationBarHeight: navigationHeight, topPadding: self.state.displayingMapModeOptions ? optionsHeight : 0.0, controlsTopPadding: 0.0, controlsBottomPadding: 0.0, offset: 0.0, size: CGSize(width: headerFrame.width, height: headerHeight), transition: transition) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) @@ -982,18 +994,118 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan let listFrame: CGRect = CGRect(origin: CGPoint(), size: layout.size) transition.updateFrame(node: self.listNode, frame: listFrame) + + if !self.isPreview { + let topEdgeEffectFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: 80.0)) + transition.updateFrame(view: self.topEdgeEffectView, frame: topEdgeEffectFrame) + self.topEdgeEffectView.update(content: self.headerNode.mapNode.mapMode == .map ? self.presentationData.theme.list.plainBackgroundColor : .clear, blur: true, alpha: 0.65, rect: topEdgeEffectFrame, edge: .top, edgeSize: topEdgeEffectFrame.height, transition: ComponentTransition(transition)) + if self.topEdgeEffectView.superview == nil { + self.view.addSubview(self.topEdgeEffectView) + } + + let leftControlItems: [GlassControlGroupComponent.Item] = [ + GlassControlGroupComponent.Item( + id: AnyHashable("close"), + content: .icon("Navigation/Close"), + action: { [weak self] in + guard let self else { + return + } + self.controller?.dismiss() + } + ) + ] + var rightControlItems: [GlassControlGroupComponent.Item] = [] + switch self.rightBarButtonAction { + case .none: + break + case .share: + rightControlItems.append( + GlassControlGroupComponent.Item( + id: AnyHashable("share"), + content: .icon("Navigation/Share"), + action: { [weak self] in + guard let self else { + return + } + self.interaction.share() + } + ) + ) + case .showAll: + rightControlItems.append( + GlassControlGroupComponent.Item( + id: AnyHashable("share"), + content: .text(self.presentationData.strings.Map_LiveLocationShowAll), + action: { [weak self] in + guard let self else { + return + } + self.showAll() + } + ) + ) + } + + let barButtonSideInset: CGFloat = 16.0 + let buttonsSize = self.buttons.update( + transition: ComponentTransition(transition), + component: AnyComponent(GlassControlPanelComponent( + theme: self.presentationData.theme, + leftItem: GlassControlPanelComponent.Item( + items: leftControlItems, + background: .panel + ), + centralItem: nil, + rightItem: rightControlItems.isEmpty ? nil : GlassControlPanelComponent.Item( + items: rightControlItems, + background: .panel + ), + centerAlignmentIfPossible: true, + isDark: self.presentationData.theme.overallDarkAppearance + )), + environment: {}, + containerSize: CGSize(width: layout.size.width - barButtonSideInset * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: 44.0) + ) + let buttonsFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: buttonsSize) + if let view = self.buttons.view { + if view.superview == nil { + self.view.addSubview(view) + } + view.bounds = CGRect(origin: .zero, size: buttonsFrame.size) + view.center = buttonsFrame.center + } + + let titleSize = self.title.update( + transition: ComponentTransition(transition), + component: AnyComponent( + MultilineTextComponent( + text: .plain( + NSAttributedString( + string: self.presentationData.strings.Map_LocationTitle, + font: Font.semibold(17.0), + textColor: self.headerNode.mapNode.mapMode == .map ? self.presentationData.theme.rootController.navigationBar.primaryTextColor : .white + ) + ) + ) + ), + environment: {}, + containerSize: CGSize(width: 200.0, height: 40.0) + ) + let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - titleSize.width) / 2.0), y: floorToScreenPixels((navigationHeight - titleSize.height) / 2.0) + 3.0), size: titleSize) + if let titleView = self.title.view { + if titleView.superview == nil { + self.view.addSubview(titleView) + } + transition.updateFrame(view: titleView, frame: titleFrame) + } + } if isFirstLayout { while !self.enqueuedTransitions.isEmpty { self.dequeueTransition() } } - - let optionsOffset: CGFloat = self.state.displayingMapModeOptions ? navigationHeight : navigationHeight - optionsHeight - let optionsFrame = CGRect(x: 0.0, y: optionsOffset, width: layout.size.width, height: optionsHeight) - transition.updateFrame(node: self.optionsNode, frame: optionsFrame) - self.optionsNode.updateLayout(size: optionsFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: transition) - self.optionsNode.isUserInteractionEnabled = self.state.displayingMapModeOptions } var coordinate: Signal { diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 12a60b459f..62e456fc28 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -240,8 +240,6 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att private let cancelButtonNode: WebAppCancelButtonNode private var buttons: ComponentView? - private var cancelButton: ComponentView? - private var rightButton: ComponentView? private let moreButtonPlayOnce = ActionSlot() private let moreButtonNode: MoreButtonNode @@ -2104,7 +2102,6 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att } if case .glass = style { - self.cancelButton = ComponentView() self.buttons = ComponentView() } self.cancelButtonNode = WebAppCancelButtonNode(theme: self.presentationData.theme, strings: self.presentationData.strings) diff --git a/submodules/MimeTypes/Sources/TGMimeTypeMap.m b/submodules/MimeTypes/Sources/TGMimeTypeMap.m index 76d7fe9f65..894c12aa66 100644 --- a/submodules/MimeTypes/Sources/TGMimeTypeMap.m +++ b/submodules/MimeTypes/Sources/TGMimeTypeMap.m @@ -250,6 +250,7 @@ static void initializeMapping() mimeToExtension[@"text/plain"] = @"text"; extensionToMime[@"text"] = @"text/plain"; mimeToExtension[@"text/plain"] = @"diff"; extensionToMime[@"diff"] = @"text/plain"; mimeToExtension[@"text/plain"] = @"po"; extensionToMime[@"po"] = @"text/plain"; // reserve "pot" for vnd.ms-powerpoint + mimeToExtension[@"text/markdown"] = @"md"; extensionToMime[@"md"] = @"text/markdown"; mimeToExtension[@"text/richtext"] = @"rtx"; extensionToMime[@"rtx"] = @"text/richtext"; mimeToExtension[@"text/rtf"] = @"rtf"; extensionToMime[@"rtf"] = @"text/rtf"; mimeToExtension[@"text/texmacs"] = @"ts"; extensionToMime[@"ts"] = @"text/texmacs"; diff --git a/submodules/ShareController/Sources/SharePeersContainerNode.swift b/submodules/ShareController/Sources/SharePeersContainerNode.swift index 63caa2459c..7f82934154 100644 --- a/submodules/ShareController/Sources/SharePeersContainerNode.swift +++ b/submodules/ShareController/Sources/SharePeersContainerNode.swift @@ -373,7 +373,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.contentOffsetUpdated = f } - private func calculateMetrics(size: CGSize, additionalBottomInset: CGFloat) -> (topInset: CGFloat, itemWidth: CGFloat) { + private func calculateMetrics(size: CGSize, additionalBottomInset: CGFloat, isEmbedded: Bool) -> (topInset: CGFloat, itemWidth: CGFloat) { let itemCount = self.entries.count let itemInsets = UIEdgeInsets(top: 0.0, left: 12.0, bottom: 0.0, right: 12.0) @@ -394,7 +394,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { } let initiallyRevealedRowCount = min(minimallyRevealedRowCount, CGFloat(rowCount)) - let gridTopInset = max(0.0, size.height - floor(initiallyRevealedRowCount * itemWidth) - 14.0 - additionalBottomInset) + let gridTopInset = isEmbedded ? 136.0 : max(0.0, size.height - floor(initiallyRevealedRowCount * itemWidth) - 14.0 - additionalBottomInset) return (gridTopInset, itemWidth) } @@ -569,10 +569,15 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { } } + var isEmbedded = false func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let firstLayout = self.validLayout == nil self.validLayout = (size, bottomInset) + self.contentTitleNode.isHidden = self.isEmbedded + self.contentSubtitleNode.isHidden = self.isEmbedded + self.searchButtonNode.isHidden = self.isEmbedded + let gridLayoutTransition: ContainedViewLayoutTransition if firstLayout { gridLayoutTransition = .immediate @@ -582,7 +587,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.overrideGridOffsetTransition = nil } - let (gridTopInset, itemWidth) = self.calculateMetrics(size: size, additionalBottomInset: bottomInset) + let (gridTopInset, itemWidth) = self.calculateMetrics(size: size, additionalBottomInset: bottomInset, isEmbedded: self.isEmbedded) var scrollToItem: GridNodeScrollToItem? if let ensurePeerVisibleOnLayout = self.ensurePeerVisibleOnLayout { @@ -680,8 +685,8 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.contentTitleNode.isHidden = true self.contentSubtitleNode.isHidden = true } else { - self.contentTitleNode.isHidden = false - self.contentSubtitleNode.isHidden = false + self.contentTitleNode.isHidden = self.isEmbedded + self.contentSubtitleNode.isHidden = self.isEmbedded var subtitleText = self.strings.ShareMenu_SelectChats if !self.controllerInteraction.selectedPeers.isEmpty { diff --git a/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift b/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift index e7709d56fc..af2fc0010a 100644 --- a/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift +++ b/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift @@ -1413,7 +1413,7 @@ public final class SparseItemGridScrollingArea: ASDisplayNode { } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if self.dateIndicator.alpha <= 0.01 { + if self.dateIndicator.alpha <= 0.01 || !self.isDateIndicatorVisible { return nil } if self.dateIndicator.frame.offsetBy(dx: self.dateIndicatorContainer.frame.minX, dy: self.dateIndicatorContainer.frame.minY).contains(point) { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 51173eea52..b1f6611745 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -132,6 +132,12 @@ public enum PresentationResourceKey: Int32 { case chatListGiftIcon case chatListLocationIcon case chatListPollIcon + case chatListTodoIcon + case chatListGameIcon + case chatListCallIncomingIcon + case chatListCallOutgoingIcon + case chatListCallVideoIncomingIcon + case chatListCallVideoOutgoingIcon case chatListGeneralTopicIcon case chatListGeneralTopicTemplateIcon diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChatList.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChatList.swift index c0c7a791c6..2092f8b75b 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChatList.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChatList.swift @@ -313,6 +313,42 @@ public struct PresentationResourcesChatList { }) } + public static func todoIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListTodoIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/TodoIcon"), color: theme.chatList.muteIconColor) + }) + } + + public static func gameIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListGameIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GameIcon"), color: theme.chatList.muteIconColor) + }) + } + + public static func callIncomingIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListCallIncomingIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/CallIncomingIcon"), color: theme.chatList.muteIconColor) + }) + } + + public static func callOutgoingIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListCallOutgoingIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/CallOutgoingIcon"), color: theme.chatList.muteIconColor) + }) + } + + public static func callVideoIncomingIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListCallVideoIncomingIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/CallVideoIncomingIcon"), color: theme.chatList.muteIconColor) + }) + } + + public static func callVideoOutgoingIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatListCallVideoOutgoingIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat List/CallVideoOutgoingIcon"), color: theme.chatList.muteIconColor) + }) + } + public static func verifiedIcon(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.chatListVerifiedIcon.rawValue, { theme in if let backgroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconForeground") { diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 764a33bcce..59680b35d0 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -526,6 +526,8 @@ swift_library( "//submodules/TelegramUI/Components/RankChatPreviewItem", "//submodules/TelegramUI/Components/TextProcessingScreen", "//submodules/TelegramUI/Components/CreateBotScreen", + "//submodules/TelegramUI/Components/ShareScreen", + "//submodules/Utils/AutomationBridge", ] + select({ "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "//build-system:ios_sim_arm64": [], diff --git a/submodules/TelegramUI/Components/AdminUserActionsSheet/BUILD b/submodules/TelegramUI/Components/AdminUserActionsSheet/BUILD index fd2f6c708b..c2e9d97ddd 100644 --- a/submodules/TelegramUI/Components/AdminUserActionsSheet/BUILD +++ b/submodules/TelegramUI/Components/AdminUserActionsSheet/BUILD @@ -17,6 +17,7 @@ swift_library( "//submodules/ComponentFlow", "//submodules/Components/ViewControllerComponent", "//submodules/Components/ComponentDisplayAdapters", + "//submodules/Components/ResizableSheetComponent", "//submodules/Components/MultilineTextComponent", "//submodules/Components/BundleIconComponent", "//submodules/TelegramPresentationData", diff --git a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsPeerComponent.swift b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsPeerComponent.swift index dc1f55617c..f89ecc8d9f 100644 --- a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsPeerComponent.swift +++ b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsPeerComponent.swift @@ -227,7 +227,7 @@ final class AdminUserActionsPeerComponent: Component { let titleSize = self.title.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: component.title, font: Font.semibold(component.baseFontSize), textColor: component.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: component.title, font: Font.medium(component.baseFontSize), textColor: component.theme.list.itemPrimaryTextColor)) )), environment: {}, containerSize: CGSize(width: maxTextSize, height: 100.0) diff --git a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift index 54d828be17..636318a5c4 100644 --- a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift +++ b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift @@ -1,24 +1,21 @@ import Foundation import UIKit import Display -import AsyncDisplayKit import ComponentFlow import SwiftSignalKit import ViewControllerComponent -import ComponentDisplayAdapters import TelegramPresentationData import AccountContext import TelegramCore import MultilineTextComponent import ButtonComponent import PresentationDataUtils -import Markdown -import UndoUI -import AvatarNode -import TelegramStringFormatting import ListSectionComponent import ListActionItemComponent import PlainButtonComponent +import ResizableSheetComponent +import GlassBarButtonComponent +import BundleIconComponent struct MediaRight: OptionSet, Hashable { var rawValue: Int @@ -187,6 +184,768 @@ private let allMediaRightItems: [MediaRight] = [ .polls ] +private enum AdminUserActionOptionSection { + case report + case deleteAll + case ban +} + +private enum AdminUserActionConfigItem: Hashable, CaseIterable { + case sendMessages + case sendMedia + case addUsers + case pinMessages + case changeInfo +} + +private struct AdminUserActionsSheetState: Equatable { + var isOptionReportExpanded: Bool + var optionReportSelectedPeers: Set + var isOptionDeleteAllExpanded: Bool + var optionDeleteAllSelectedPeers: Set + var optionDeleteAllReactionsSelectedPeers: Set + var isOptionBanExpanded: Bool + var optionBanSelectedPeers: Set + var isConfigurationExpanded: Bool + var isMediaSectionExpanded: Bool + var allowedParticipantRights: ParticipantRight + var allowedMediaRights: MediaRight + var participantRights: ParticipantRight + var mediaRights: MediaRight +} + +private func availableAdminUserActionOptionSections( + accountPeerId: EnginePeer.Id, + chatPeer: EnginePeer, + peers: [RenderedChannelParticipant], + mode: AdminUserActionsSheet.Mode +) -> [AdminUserActionOptionSection] { + var result: [AdminUserActionOptionSection] = [.report] + + switch mode { + case .monoforum: + result.append(.ban) + case .chat, .chatReaction: + if case let .channel(channel) = chatPeer { + if channel.hasPermission(.deleteAllMessages) { + result.append(.deleteAll) + + if channel.hasPermission(.banMembers) { + var canBanEveryone = true + for peer in peers { + if peer.peer.id == accountPeerId { + canBanEveryone = false + continue + } + + switch peer.participant { + case .creator: + canBanEveryone = false + case let .member(_, _, adminInfo, _, _, _): + if let adminInfo { + if channel.flags.contains(.isCreator) { + } else if adminInfo.promotedBy == accountPeerId { + } else { + canBanEveryone = false + } + } + } + } + + if canBanEveryone { + result.append(.ban) + } + } + } + } + case .liveStream: + result.append(.deleteAll) + result.append(.ban) + } + + return result +} + +private func adminUserActionsTitle( + strings: PresentationStrings, + mode: AdminUserActionsSheet.Mode, + peers: [RenderedChannelParticipant], + selectedDeleteAllPeers: Set +) -> String { + switch mode { + case .monoforum: + if let peer = peers.first { + return strings.Monoforum_DeleteTopic_Title(EnginePeer(peer.peer).compactDisplayTitle).string + } else { + return strings.Common_Delete + } + case let .chat(messageCount, deleteAllMessageCount, _): + if let deleteAllMessageCount, selectedDeleteAllPeers == Set(peers.map { $0.peer.id }) { + return strings.Chat_AdminActionSheet_DeleteTitle(Int32(deleteAllMessageCount)) + } else { + return strings.Chat_AdminActionSheet_DeleteTitle(Int32(messageCount)) + } + case let .liveStream(messageCount, deleteAllMessageCount, _): + if let deleteAllMessageCount, selectedDeleteAllPeers == Set(peers.map { $0.peer.id }) { + return strings.Chat_AdminActionSheet_DeleteTitle(Int32(deleteAllMessageCount)) + } else { + return strings.Chat_AdminActionSheet_DeleteTitle(Int32(messageCount)) + } + case .chatReaction(_): + //TODO:localize + return "Delete 1 Reaction" + } +} + +private final class AdminUserActionsContentComponent: Component { + typealias EnvironmentType = ViewControllerComponentContainer.Environment + + let context: AccountContext + let chatPeer: EnginePeer + let peers: [RenderedChannelParticipant] + let mode: AdminUserActionsSheet.Mode + let theme: PresentationTheme + let strings: PresentationStrings + let presentationData: PresentationData + let sheetState: AdminUserActionsSheetState + let disableOptionsSectionAnimation: Bool + let toggleOptionSelection: (AdminUserActionOptionSection) -> Void + let toggleOptionExpansion: (AdminUserActionOptionSection) -> Void + let togglePeerSelection: (AdminUserActionOptionSection, EnginePeer) -> Void + let toggleConfiguration: () -> Void + let toggleConfigItem: (AdminUserActionConfigItem) -> Void + let toggleMediaSectionExpansion: () -> Void + let toggleMediaRight: (MediaRight) -> Void + + init( + context: AccountContext, + chatPeer: EnginePeer, + peers: [RenderedChannelParticipant], + mode: AdminUserActionsSheet.Mode, + theme: PresentationTheme, + strings: PresentationStrings, + presentationData: PresentationData, + sheetState: AdminUserActionsSheetState, + disableOptionsSectionAnimation: Bool, + toggleOptionSelection: @escaping (AdminUserActionOptionSection) -> Void, + toggleOptionExpansion: @escaping (AdminUserActionOptionSection) -> Void, + togglePeerSelection: @escaping (AdminUserActionOptionSection, EnginePeer) -> Void, + toggleConfiguration: @escaping () -> Void, + toggleConfigItem: @escaping (AdminUserActionConfigItem) -> Void, + toggleMediaSectionExpansion: @escaping () -> Void, + toggleMediaRight: @escaping (MediaRight) -> Void + ) { + self.context = context + self.chatPeer = chatPeer + self.peers = peers + self.mode = mode + self.theme = theme + self.strings = strings + self.presentationData = presentationData + self.sheetState = sheetState + self.disableOptionsSectionAnimation = disableOptionsSectionAnimation + self.toggleOptionSelection = toggleOptionSelection + self.toggleOptionExpansion = toggleOptionExpansion + self.togglePeerSelection = togglePeerSelection + self.toggleConfiguration = toggleConfiguration + self.toggleConfigItem = toggleConfigItem + self.toggleMediaSectionExpansion = toggleMediaSectionExpansion + self.toggleMediaRight = toggleMediaRight + } + + static func ==(lhs: AdminUserActionsContentComponent, rhs: AdminUserActionsContentComponent) -> Bool { + return false + } + + final class View: UIView { + private let optionsSection = ComponentView() + private let optionsFooter = ComponentView() + private let configSection = ComponentView() + + func update(component: AdminUserActionsContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + let environment = environment[ViewControllerComponentContainer.Environment.self].value + let sideInset: CGFloat = 16.0 + var contentHeight: CGFloat = 76.0 + + contentHeight += 15.0 + + let availableOptions = availableAdminUserActionOptionSections( + accountPeerId: component.context.account.peerId, + chatPeer: component.chatPeer, + peers: component.peers, + mode: component.mode + ) + + let optionsItem: (AdminUserActionOptionSection) -> AnyComponentWithIdentity = { section in + let sectionId: AnyHashable + let selectedPeers: Set + var additionalSelectedPeers = Set() + let isExpanded: Bool + let title: String + + switch section { + case .report: + sectionId = "report" + selectedPeers = component.sheetState.optionReportSelectedPeers + isExpanded = component.sheetState.isOptionReportExpanded + title = component.strings.Chat_AdminActionSheet_ReportSpam + case .deleteAll: + sectionId = "delete-all" + selectedPeers = component.sheetState.optionDeleteAllSelectedPeers + additionalSelectedPeers = component.sheetState.optionDeleteAllReactionsSelectedPeers + isExpanded = component.sheetState.isOptionDeleteAllExpanded + if component.peers.count == 1 { + title = component.strings.Chat_AdminActionSheet_DeleteAllSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string + } else { + title = component.strings.Chat_AdminActionSheet_DeleteAllMultiple + } + case .ban: + sectionId = "ban" + selectedPeers = component.sheetState.optionBanSelectedPeers + isExpanded = component.sheetState.isOptionBanExpanded + + let banTitle: String + let restrictTitle: String + if component.peers.count == 1 { + banTitle = component.strings.Chat_AdminActionSheet_BanSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string + restrictTitle = component.strings.Chat_AdminActionSheet_RestrictSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string + } else { + banTitle = component.strings.Chat_AdminActionSheet_BanMultiple + restrictTitle = component.strings.Chat_AdminActionSheet_RestrictMultiple + } + title = component.sheetState.isConfigurationExpanded ? restrictTitle : banTitle + } + + var titleItems: [AnyComponentWithIdentity] = [ + AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: title, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + ))) + ] + + var accessory: ListActionItemComponent.Accessory? + var isExpandable = false + if component.peers.count > 1 { + accessory = .custom(ListActionItemComponent.CustomAccessory( + component: AnyComponentWithIdentity(id: 0, component: AnyComponent(PlainButtonComponent( + content: AnyComponent(OptionSectionExpandIndicatorComponent( + theme: component.theme, + count: selectedPeers.isEmpty ? component.peers.count : selectedPeers.count, + isExpanded: isExpanded + )), + effectAlignment: .center, + action: { + component.toggleOptionExpansion(section) + }, + animateScale: false + ))), + insets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 2.0), + isInteractive: true + )) + } else if case .deleteAll = section { + var count = 0 + if !selectedPeers.isEmpty { + count += 1 + } + if !additionalSelectedPeers.isEmpty { + count += 1 + } + titleItems.append( + AnyComponentWithIdentity(id: 1, component: AnyComponent(MediaSectionExpandIndicatorComponent( + theme: component.theme, + title: "\(count)/2", + isExpanded: component.sheetState.isMediaSectionExpanded + ))) + ) + isExpandable = true + } + + return AnyComponentWithIdentity(id: sectionId, component: AnyComponent(ListActionItemComponent( + theme: component.theme, + style: .glass, + title: AnyComponent(HStack(titleItems, spacing: 7.0)), + leftIcon: .check(ListActionItemComponent.LeftIcon.Check( + isSelected: !selectedPeers.isEmpty || !additionalSelectedPeers.isEmpty, + toggle: { + component.toggleOptionSelection(section) + } + )), + icon: .none, + accessory: accessory, + action: { _ in + if isExpandable { + component.toggleOptionExpansion(section) + } else { + component.toggleOptionSelection(section) + } + }, + highlighting: .disabled + ))) + } + + let expandedPeersItem: (AdminUserActionOptionSection) -> AnyComponentWithIdentity = { section in + let sectionId: AnyHashable + let selectedPeers: Set + var additionalSelectedPeers = Set() + switch section { + case .report: + sectionId = "report-peers" + selectedPeers = component.sheetState.optionReportSelectedPeers + case .deleteAll: + sectionId = "delete-all-peers" + selectedPeers = component.sheetState.optionDeleteAllSelectedPeers + additionalSelectedPeers = component.sheetState.optionDeleteAllReactionsSelectedPeers + case .ban: + sectionId = "ban-peers" + selectedPeers = component.sheetState.optionBanSelectedPeers + } + + var subItems: [AnyComponentWithIdentity] = [] + if component.peers.count > 1 { + for peer in component.peers { + subItems.append(AnyComponentWithIdentity(id: peer.peer.id, component: AnyComponent(AdminUserActionsPeerComponent( + context: component.context, + theme: component.theme, + strings: component.strings, + baseFontSize: component.presentationData.listsFontSize.baseDisplaySize, + sideInset: 0.0, + title: EnginePeer(peer.peer).displayTitle(strings: component.strings, displayOrder: .firstLast), + peer: EnginePeer(peer.peer), + selectionState: .editing(isSelected: selectedPeers.contains(peer.peer.id)), + action: { peer in + component.togglePeerSelection(section, peer) + } + )))) + } + } else { + //TODO:localize + subItems.append( + AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( + theme: component.theme, + style: .glass, + title: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: "Delete all Messages", + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )), + leftIcon: .check(ListActionItemComponent.LeftIcon.Check( + isSelected: !selectedPeers.isEmpty, + toggle: { + component.toggleOptionSelection(section) + } + )), + icon: .none, + accessory: nil, + action: { _ in + component.toggleOptionSelection(section) + }, + highlighting: .disabled + ))) + ) + subItems.append( + AnyComponentWithIdentity(id: 1, component: AnyComponent(ListActionItemComponent( + theme: component.theme, + style: .glass, + title: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: "Delete all Reactions", + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )), + leftIcon: .check(ListActionItemComponent.LeftIcon.Check( + isSelected: !additionalSelectedPeers.isEmpty, + toggle: { + component.toggleOptionSelection(section) + } + )), + icon: .none, + accessory: nil, + action: { _ in + component.toggleOptionSelection(section) + }, + highlighting: .disabled + ))) + ) + } + + return AnyComponentWithIdentity(id: sectionId, component: AnyComponent(ListSubSectionComponent( + theme: component.theme, + leftInset: 43.0, + items: subItems + ))) + } + + var optionsSectionItems: [AnyComponentWithIdentity] = [] + for option in availableOptions { + let isExpanded: Bool + switch option { + case .report: + isExpanded = component.sheetState.isOptionReportExpanded + case .deleteAll: + isExpanded = component.sheetState.isOptionDeleteAllExpanded + case .ban: + isExpanded = component.sheetState.isOptionBanExpanded + } + + optionsSectionItems.append(optionsItem(option)) + if isExpanded { + optionsSectionItems.append(expandedPeersItem(option)) + } + } + + let optionsSectionTransition: ComponentTransition = component.disableOptionsSectionAnimation ? transition.withAnimation(.none) : transition + let optionsSectionSize = self.optionsSection.update( + transition: optionsSectionTransition, + component: AnyComponent(ListSectionComponent( + theme: component.theme, + style: .glass, + header: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Chat_AdminActionSheet_RestrictSectionHeader, + font: Font.regular(component.presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: component.theme.list.freeTextColor + )), + maximumNumberOfLines: 0 + )), + footer: nil, + items: optionsSectionItems, + isModal: true + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0) + ) + let optionsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: optionsSectionSize) + self.optionsSection.parentState = state + if let optionsSectionView = self.optionsSection.view { + if optionsSectionView.superview == nil { + self.addSubview(optionsSectionView) + } + transition.setFrame(view: optionsSectionView, frame: optionsSectionFrame) + } + contentHeight += optionsSectionSize.height + + let partiallyRestrictTitle: String + let fullyBanTitle: String + if component.peers.count == 1 { + partiallyRestrictTitle = component.strings.Chat_AdminActionSheet_RestrictFooterSingle + fullyBanTitle = component.strings.Chat_AdminActionSheet_BanFooterSingle + } else { + partiallyRestrictTitle = component.strings.Chat_AdminActionSheet_RestrictFooterMultiple + fullyBanTitle = component.strings.Chat_AdminActionSheet_BanFooterMultiple + } + + let optionsFooterSize = self.optionsFooter.update( + transition: transition, + component: AnyComponent(PlainButtonComponent( + content: AnyComponent(OptionsSectionFooterComponent( + theme: component.theme, + text: component.sheetState.isConfigurationExpanded ? fullyBanTitle : partiallyRestrictTitle, + fontSize: component.presentationData.listsFontSize.itemListBaseHeaderFontSize, + isExpanded: component.sheetState.isConfigurationExpanded + )), + effectAlignment: .left, + contentInsets: UIEdgeInsets(), + action: { + component.toggleConfiguration() + }, + animateAlpha: true, + animateScale: false, + animateContents: true + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + ) + + var configSectionItems: [AnyComponentWithIdentity] = [] + + if case let .channel(channel) = component.chatPeer, channel.isMonoForum { + } else if case .liveStream = component.mode { + } else { + var allConfigItems: [(AdminUserActionConfigItem, Bool)] = [] + if !component.sheetState.allowedMediaRights.isEmpty || !component.sheetState.allowedParticipantRights.isEmpty { + for configItem in AdminUserActionConfigItem.allCases { + let isEnabled: Bool + switch configItem { + case .sendMessages: + isEnabled = component.sheetState.allowedParticipantRights.contains(.sendMessages) + case .sendMedia: + isEnabled = !component.sheetState.allowedMediaRights.isEmpty + case .addUsers: + isEnabled = component.sheetState.allowedParticipantRights.contains(.addMembers) + case .pinMessages: + isEnabled = component.sheetState.allowedParticipantRights.contains(.pinMessages) + case .changeInfo: + isEnabled = component.sheetState.allowedParticipantRights.contains(.changeInfo) + } + allConfigItems.append((configItem, isEnabled)) + } + } + + for (configItem, isEnabled) in allConfigItems { + let itemTitle: AnyComponent + let itemValue: Bool + switch configItem { + case .sendMessages: + itemTitle = AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_BanUser_PermissionSendMessages, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )) + itemValue = component.sheetState.participantRights.contains(.sendMessages) + case .sendMedia: + if isEnabled { + itemTitle = AnyComponent(HStack([ + AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_BanUser_PermissionSendMedia, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + ))), + AnyComponentWithIdentity(id: 1, component: AnyComponent(MediaSectionExpandIndicatorComponent( + theme: component.theme, + title: "\(component.sheetState.mediaRights.count)/\(component.sheetState.allowedMediaRights.count)", + isExpanded: component.sheetState.isMediaSectionExpanded + ))) + ], spacing: 7.0)) + } else { + itemTitle = AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_BanUser_PermissionSendMedia, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )) + } + itemValue = !component.sheetState.mediaRights.isEmpty + case .addUsers: + itemTitle = AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_BanUser_PermissionAddMembers, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )) + itemValue = component.sheetState.participantRights.contains(.addMembers) + case .pinMessages: + itemTitle = AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_EditAdmin_PermissionPinMessages, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )) + itemValue = component.sheetState.participantRights.contains(.pinMessages) + case .changeInfo: + itemTitle = AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.strings.Channel_BanUser_PermissionChangeGroupInfo, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )) + itemValue = component.sheetState.participantRights.contains(.changeInfo) + } + + configSectionItems.append(AnyComponentWithIdentity(id: configItem, component: AnyComponent(ListActionItemComponent( + theme: component.theme, + style: .glass, + title: itemTitle, + accessory: .toggle(ListActionItemComponent.Toggle( + style: isEnabled ? .icons : .lock, + isOn: itemValue, + isInteractive: isEnabled, + action: isEnabled ? { _ in + component.toggleConfigItem(configItem) + } : nil + )), + action: ((isEnabled && configItem == .sendMedia) || !isEnabled) ? { _ in + if !isEnabled { + environment.controller()?.present(textAlertController( + context: component.context, + title: nil, + text: component.strings.GroupPermission_PermissionDisabledByDefault, + actions: [ + TextAlertAction(type: .defaultAction, title: component.strings.Common_OK, action: { + }) + ] + ), in: .window(.root)) + } else { + component.toggleMediaSectionExpansion() + } + } : nil, + highlighting: .disabled + )))) + + if isEnabled, case .sendMedia = configItem, component.sheetState.isMediaSectionExpanded { + var mediaItems: [AnyComponentWithIdentity] = [] + mediaRightsLoop: for possibleMediaItem in allMediaRightItems { + if !component.sheetState.allowedMediaRights.contains(possibleMediaItem) { + continue + } + + let mediaItemTitle: String + switch possibleMediaItem { + case .photos: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendPhoto + case .videos: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendVideo + case .stickersAndGifs: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendStickersAndGifs + case .music: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendMusic + case .files: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendFile + case .voiceMessages: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendVoiceMessage + case .videoMessages: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendVideoMessage + case .links: + mediaItemTitle = component.strings.Channel_BanUser_PermissionEmbedLinks + case .polls: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendPolls + default: + continue mediaRightsLoop + } + + mediaItems.append(AnyComponentWithIdentity(id: possibleMediaItem, component: AnyComponent(ListActionItemComponent( + theme: component.theme, + style: .glass, + title: AnyComponent(VStack([ + AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: mediaItemTitle, + font: Font.regular(component.presentationData.listsFontSize.baseDisplaySize), + textColor: component.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + ))) + ], alignment: .left, spacing: 2.0)), + leftIcon: .check(ListActionItemComponent.LeftIcon.Check( + isSelected: component.sheetState.mediaRights.contains(possibleMediaItem), + toggle: { + component.toggleMediaRight(possibleMediaItem) + } + )), + icon: .none, + accessory: .none, + action: { _ in + component.toggleMediaRight(possibleMediaItem) + }, + highlighting: .disabled + )))) + } + configSectionItems.append(AnyComponentWithIdentity(id: "media-sub", component: AnyComponent(ListSubSectionComponent( + theme: component.theme, + leftInset: 0.0, + items: mediaItems + )))) + } + } + } + + let configSectionSize = self.configSection.update( + transition: transition, + component: AnyComponent(ListSectionComponent( + theme: component.theme, + style: .glass, + header: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.peers.count == 1 ? component.strings.Chat_AdminActionSheet_PermissionsSectionHeader : component.strings.Chat_AdminActionSheet_PermissionsSectionHeaderMultiple, + font: Font.regular(component.presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: component.theme.list.freeTextColor + )), + maximumNumberOfLines: 0 + )), + footer: nil, + items: configSectionItems + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0) + ) + let configSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight + 30.0), size: configSectionSize) + self.configSection.parentState = state + if let configSectionView = self.configSection.view { + if configSectionView.superview == nil { + configSectionView.clipsToBounds = true + configSectionView.layer.cornerRadius = 11.0 + self.addSubview(configSectionView) + } + let effectiveConfigSectionFrame: CGRect + if component.sheetState.isConfigurationExpanded { + effectiveConfigSectionFrame = configSectionFrame + } else { + effectiveConfigSectionFrame = CGRect(origin: CGPoint(x: configSectionFrame.minX, y: configSectionFrame.minY - 30.0), size: CGSize(width: configSectionFrame.width, height: 0.0)) + } + transition.setFrame(view: configSectionView, frame: effectiveConfigSectionFrame) + transition.setAlpha(view: configSectionView, alpha: component.sheetState.isConfigurationExpanded ? 1.0 : 0.0) + } + + if availableOptions.contains(.ban) && !configSectionItems.isEmpty { + let optionsFooterFrame: CGRect + if component.sheetState.isConfigurationExpanded { + contentHeight += 30.0 + contentHeight += configSectionSize.height + contentHeight += 7.0 + optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) + contentHeight += optionsFooterSize.height + } else { + contentHeight += 7.0 + optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) + contentHeight += optionsFooterSize.height + } + self.optionsFooter.parentState = state + if let optionsFooterView = self.optionsFooter.view { + if optionsFooterView.superview == nil { + self.addSubview(optionsFooterView) + } + transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame) + transition.setAlpha(view: optionsFooterView, alpha: 1.0) + } + } else { + self.optionsFooter.parentState = state + if let optionsFooterView = self.optionsFooter.view { + if optionsFooterView.superview == nil { + self.addSubview(optionsFooterView) + } + let optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) + transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame) + transition.setAlpha(view: optionsFooterView, alpha: 0.0) + } + } + + contentHeight += 36.0 + 52.0 + 30.0 + + return CGSize(width: availableSize.width, height: contentHeight) + } + } + + func makeView() -> View { + return View(frame: CGRect()) + } + + func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} + private final class AdminUserActionsSheetComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -211,57 +970,15 @@ private final class AdminUserActionsSheetComponent: Component { return true } - private struct ItemLayout: Equatable { - var containerSize: CGSize - var containerInset: CGFloat - var bottomInset: CGFloat - var topInset: CGFloat - - init(containerSize: CGSize, containerInset: CGFloat, bottomInset: CGFloat, topInset: CGFloat) { - self.containerSize = containerSize - self.containerInset = containerInset - self.bottomInset = bottomInset - self.topInset = topInset - } - } - - private final class ScrollView: UIScrollView { - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - return super.hitTest(point, with: event) - } - } - - final class View: UIView, UIScrollViewDelegate { - private let dimView: UIView - private let backgroundLayer: SimpleLayer - private let navigationBarContainer: SparseContainerView - private let navigationBackgroundView: BlurredBackgroundView - private let navigationBarSeparator: SimpleLayer - private let scrollView: ScrollView - private let scrollContentClippingView: SparseContainerView - private let scrollContentView: UIView - - private let leftButton = ComponentView() - - private let title = ComponentView() - private let actionButton = ComponentView() - - private let optionsSection = ComponentView() - private let optionsFooter = ComponentView() - private let configSection = ComponentView() - - private let bottomOverscrollLimit: CGFloat - - private var ignoreScrolling: Bool = false + final class View: UIView { + private let sheet = ComponentView<(ViewControllerComponentContainer.Environment, ResizableSheetComponentEnvironment)>() + private let animateOut = ActionSlot>() private var component: AdminUserActionsSheetComponent? private weak var state: EmptyComponentState? private var environment: ViewControllerComponentContainer.Environment? private var isUpdating: Bool = false - - private var itemLayout: ItemLayout? - - private var topOffsetDistance: CGFloat? + private var isDismissing: Bool = false private var isOptionReportExpanded: Bool = false private var optionReportSelectedPeers = Set() @@ -281,110 +998,13 @@ private final class AdminUserActionsSheetComponent: Component { private var previousWasConfigurationExpanded: Bool = false override init(frame: CGRect) { - self.bottomOverscrollLimit = 200.0 - - self.dimView = UIView() - - self.backgroundLayer = SimpleLayer() - self.backgroundLayer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] - self.backgroundLayer.cornerRadius = 10.0 - - self.navigationBarContainer = SparseContainerView() - - self.navigationBackgroundView = BlurredBackgroundView(color: .clear, enableBlur: true) - self.navigationBarSeparator = SimpleLayer() - - self.scrollView = ScrollView() - - self.scrollContentClippingView = SparseContainerView() - self.scrollContentClippingView.clipsToBounds = true - - self.scrollContentView = UIView() - super.init(frame: frame) - - self.addSubview(self.dimView) - self.layer.addSublayer(self.backgroundLayer) - - self.scrollView.delaysContentTouches = true - self.scrollView.canCancelContentTouches = true - self.scrollView.clipsToBounds = false - if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { - self.scrollView.contentInsetAdjustmentBehavior = .never - } - if #available(iOS 13.0, *) { - self.scrollView.automaticallyAdjustsScrollIndicatorInsets = false - } - self.scrollView.showsVerticalScrollIndicator = false - self.scrollView.showsHorizontalScrollIndicator = false - self.scrollView.alwaysBounceHorizontal = false - self.scrollView.alwaysBounceVertical = true - self.scrollView.scrollsToTop = false - self.scrollView.delegate = self - self.scrollView.clipsToBounds = true - - self.addSubview(self.scrollContentClippingView) - self.scrollContentClippingView.addSubview(self.scrollView) - - self.scrollView.addSubview(self.scrollContentView) - - self.addSubview(self.navigationBarContainer) - - self.navigationBarContainer.addSubview(self.navigationBackgroundView) - self.navigationBarContainer.layer.addSublayer(self.navigationBarSeparator) - - self.dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:)))) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - func scrollViewDidScroll(_ scrollView: UIScrollView) { - if !self.ignoreScrolling { - self.updateScrolling(transition: .immediate) - } - } - - func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { - /*guard let itemLayout = self.itemLayout, let topOffsetDistance = self.topOffsetDistance else { - return - } - - var topOffset = -self.scrollView.bounds.minY + itemLayout.topInset - topOffset = max(0.0, topOffset) - - if topOffset < topOffsetDistance { - targetContentOffset.pointee.y = scrollView.contentOffset.y - scrollView.setContentOffset(CGPoint(x: 0.0, y: itemLayout.topInset), animated: true) - }*/ - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if !self.bounds.contains(point) { - return nil - } - if !self.backgroundLayer.frame.contains(point) { - return self.dimView - } - - if let result = self.navigationBarContainer.hitTest(self.convert(point, to: self.navigationBarContainer), with: event) { - return result - } - - let result = super.hitTest(point, with: event) - return result - } - - @objc private func dimTapGesture(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { - guard let environment = self.environment, let controller = environment.controller() else { - return - } - controller.dismiss() - } - } - private func calculateMonoforumResult() -> AdminUserActionsSheet.MonoforumResult { return AdminUserActionsSheet.MonoforumResult( ban: !self.optionBanSelectedPeers.isEmpty, @@ -395,6 +1015,7 @@ private final class AdminUserActionsSheetComponent: Component { private func calculateChatResult() -> AdminUserActionsSheet.ChatResult { var reportSpamPeers: [EnginePeer.Id] = [] var deleteAllFromPeers: [EnginePeer.Id] = [] + var deleteAllReactionsFromPeers: [EnginePeer.Id] = [] var banPeers: [EnginePeer.Id] = [] var updateBannedRights: [EnginePeer.Id: TelegramChatBannedRights] = [:] @@ -405,14 +1026,16 @@ private final class AdminUserActionsSheetComponent: Component { deleteAllFromPeers.append(id) } + for id in self.optionDeleteAllSelectedPeers.sorted() { + deleteAllReactionsFromPeers.append(id) + } + if !self.isConfigurationExpanded { for id in self.optionBanSelectedPeers.sorted() { banPeers.append(id) } } else { - var banFlags: TelegramChatBannedRightsFlags = [] - banFlags = rightFlagsFromRights(participantRights: self.participantRights, mediaRights: self.mediaRights) - + let banFlags = rightFlagsFromRights(participantRights: self.participantRights, mediaRights: self.mediaRights) let bannedRights = TelegramChatBannedRights(flags: banFlags, untilDate: Int32.max) for id in self.optionBanSelectedPeers.sorted() { updateBannedRights[id] = bannedRights @@ -422,12 +1045,13 @@ private final class AdminUserActionsSheetComponent: Component { return AdminUserActionsSheet.ChatResult( reportSpamPeers: reportSpamPeers, deleteAllFromPeers: deleteAllFromPeers, + deleteAllReactionsFromPeers: deleteAllReactionsFromPeers, banPeers: banPeers, updateBannedRights: updateBannedRights ) } - private func calculateLiveStreamResult() -> AdminUserActionsSheet.LiveStreamResult { + private func calculateLiveStreamResult() -> AdminUserActionsSheet.LiveStreamResult { return AdminUserActionsSheet.LiveStreamResult( reportSpam: !self.optionReportSelectedPeers.isEmpty, deleteAll: !self.optionDeleteAllSelectedPeers.isEmpty, @@ -435,85 +1059,16 @@ private final class AdminUserActionsSheetComponent: Component { ) } - private func updateScrolling(transition: ComponentTransition) { - guard let environment = self.environment, let controller = environment.controller(), let itemLayout = self.itemLayout else { - return - } - var topOffset = -self.scrollView.bounds.minY + itemLayout.topInset - - let navigationAlpha: CGFloat = 1.0 - max(0.0, min(1.0, (topOffset + 20.0) / 20.0)) - transition.setAlpha(view: self.navigationBackgroundView, alpha: navigationAlpha) - transition.setAlpha(layer: self.navigationBarSeparator, alpha: navigationAlpha) - - topOffset = max(0.0, topOffset) - transition.setTransform(layer: self.backgroundLayer, transform: CATransform3DMakeTranslation(0.0, topOffset + itemLayout.containerInset, 0.0)) - - transition.setPosition(view: self.navigationBarContainer, position: CGPoint(x: 0.0, y: topOffset + itemLayout.containerInset)) - - let topOffsetDistance: CGFloat = min(200.0, floor(itemLayout.containerSize.height * 0.25)) - self.topOffsetDistance = topOffsetDistance - var topOffsetFraction = topOffset / topOffsetDistance - topOffsetFraction = max(0.0, min(1.0, topOffsetFraction)) - - let transitionFactor: CGFloat = 1.0 - topOffsetFraction - if self.isUpdating { - DispatchQueue.main.async { [weak controller] in - guard let controller else { - return - } - controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition) - } - } else { - controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition) - } - } - - func animateIn() { - self.dimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) - let animateOffset: CGFloat = self.bounds.height - self.backgroundLayer.frame.minY - self.scrollContentClippingView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - self.backgroundLayer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - self.navigationBarContainer.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - if let actionButtonView = self.actionButton.view { - actionButtonView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - } - } - - func animateOut(completion: @escaping () -> Void) { - let animateOffset: CGFloat = self.bounds.height - self.backgroundLayer.frame.minY - - self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) - self.scrollContentClippingView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in - completion() - }) - self.backgroundLayer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true) - self.navigationBarContainer.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true) - if let actionButtonView = self.actionButton.view { - actionButtonView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true) - } - - if let environment = self.environment, let controller = environment.controller() { - controller.updateModalStyleOverlayTransitionFactor(0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) - } - } - func update(component: AdminUserActionsSheetComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.isUpdating = true defer { self.isUpdating = false } - let environment = environment[ViewControllerComponentContainer.Environment.self].value - let themeUpdated = self.environment?.theme !== environment.theme - - let resetScrolling = self.scrollView.bounds.width != availableSize.width - - let sideInset: CGFloat = 16.0 + environment.safeInsets.left - if self.component == nil { let _ = (component.context.account.postbox.peerView(id: component.chatPeer.id) |> take(1)).start(next: { [weak self] peerView in - guard let self else{ + guard let self else { return } @@ -582,188 +1137,90 @@ private final class AdminUserActionsSheetComponent: Component { self.component = component self.state = state - self.environment = environment - if themeUpdated { - self.dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5) - self.backgroundLayer.backgroundColor = environment.theme.actionSheet.opaqueItemBackgroundColor.cgColor - - self.navigationBackgroundView.updateColor(color: environment.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) - self.navigationBarSeparator.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor - } + let environmentValue = environment[ViewControllerComponentContainer.Environment.self].value + self.environment = environmentValue + let controller = environmentValue.controller + let theme = environmentValue.theme.withModalBlocksBackground() let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }) - transition.setFrame(view: self.dimView, frame: CGRect(origin: CGPoint(), size: availableSize)) - - var contentHeight: CGFloat = 0.0 - contentHeight += 54.0 - contentHeight += 16.0 - - let leftButtonSize = self.leftButton.update( - transition: transition, - component: AnyComponent(Button( - content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)), - action: { [weak self] in - guard let self, let controller = self.environment?.controller() else { - return - } - controller.dismiss() + let dismiss: (Bool) -> Void = { [weak self] animated in + guard let self, !self.isDismissing else { + return + } + self.isDismissing = true + + let performDismiss: () -> Void = { + if let controller = controller() as? AdminUserActionsSheet { + controller.completePendingDismiss() + controller.dismiss(animated: false) } - ).minSize(CGSize(width: 44.0, height: 56.0))), - environment: {}, - containerSize: CGSize(width: 120.0, height: 100.0) + } + + if animated { + self.animateOut.invoke(Action { _ in + performDismiss() + }) + } else { + performDismiss() + } + } + + let disableOptionsSectionAnimation = self.previousWasConfigurationExpanded != self.isConfigurationExpanded + self.previousWasConfigurationExpanded = self.isConfigurationExpanded + + let currentState = AdminUserActionsSheetState( + isOptionReportExpanded: self.isOptionReportExpanded, + optionReportSelectedPeers: self.optionReportSelectedPeers, + isOptionDeleteAllExpanded: self.isOptionDeleteAllExpanded, + optionDeleteAllSelectedPeers: self.optionDeleteAllSelectedPeers, + optionDeleteAllReactionsSelectedPeers: self.optionDeleteAllSelectedPeers, + isOptionBanExpanded: self.isOptionBanExpanded, + optionBanSelectedPeers: self.optionBanSelectedPeers, + isConfigurationExpanded: self.isConfigurationExpanded, + isMediaSectionExpanded: self.isMediaSectionExpanded, + allowedParticipantRights: self.allowedParticipantRights, + allowedMediaRights: self.allowedMediaRights, + participantRights: self.participantRights, + mediaRights: self.mediaRights ) - let leftButtonFrame = CGRect(origin: CGPoint(x: 16.0 + environment.safeInsets.left, y: 0.0), size: leftButtonSize) - if let leftButtonView = self.leftButton.view { - if leftButtonView.superview == nil { - self.navigationBarContainer.addSubview(leftButtonView) + + let performMainAction: () -> Void = { [weak self] in + guard let self, let component = self.component else { + return + } + let monoforumResult = self.calculateMonoforumResult() + let chatResult = self.calculateChatResult() + let liveStreamResult = self.calculateLiveStreamResult() + + dismiss(true) + + switch component.mode { + case let .monoforum(completion): + completion(monoforumResult) + case let .chat(_, _, completion): + completion(chatResult) + case let .liveStream(_, _, completion): + completion(liveStreamResult) + case let .chatReaction(completion): + completion(chatResult) } - transition.setFrame(view: leftButtonView, frame: leftButtonFrame) } - let containerInset: CGFloat = environment.statusBarHeight + 10.0 - - let clippingY: CGFloat - - enum OptionsSection { - case report - case deleteAll - case ban - } - - var availableOptions: [OptionsSection] = [] - availableOptions.append(.report) - - switch component.mode { - case .monoforum: - availableOptions.append(.ban) - case .chat: - if case let .channel(channel) = component.chatPeer { - if channel.hasPermission(.deleteAllMessages) { - availableOptions.append(.deleteAll) - - if channel.hasPermission(.banMembers) { - var canBanEveryone = true - for peer in component.peers { - if peer.peer.id == component.context.account.peerId { - canBanEveryone = false - continue - } - - switch peer.participant { - case .creator: - canBanEveryone = false - case let .member(_, _, adminInfo, banInfo, _, _): - let _ = banInfo - if let adminInfo { - if channel.flags.contains(.isCreator) { - } else if adminInfo.promotedBy == component.context.account.peerId { - } else { - canBanEveryone = false - } - } - } - } - - if canBanEveryone { - availableOptions.append(.ban) - } - } - } - } - case .liveStream: - availableOptions.append(.deleteAll) - availableOptions.append(.ban) - } - - let optionsItem: (OptionsSection) -> AnyComponentWithIdentity = { section in - let sectionId: AnyHashable - let selectedPeers: Set - let isExpanded: Bool - var title: String - - switch section { - case .report: - sectionId = "report" - selectedPeers = self.optionReportSelectedPeers - isExpanded = self.isOptionReportExpanded - - title = environment.strings.Chat_AdminActionSheet_ReportSpam - case .deleteAll: - sectionId = "delete-all" - selectedPeers = self.optionDeleteAllSelectedPeers - isExpanded = self.isOptionDeleteAllExpanded - - if component.peers.count == 1 { - title = environment.strings.Chat_AdminActionSheet_DeleteAllSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string - } else { - title = environment.strings.Chat_AdminActionSheet_DeleteAllMultiple - } - case .ban: - sectionId = "ban" - selectedPeers = self.optionBanSelectedPeers - isExpanded = self.isOptionBanExpanded - - let banTitle: String - let restrictTitle: String - if component.peers.count == 1 { - banTitle = environment.strings.Chat_AdminActionSheet_BanSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string - restrictTitle = environment.strings.Chat_AdminActionSheet_RestrictSingle(EnginePeer(component.peers[0].peer).compactDisplayTitle).string - } else { - banTitle = environment.strings.Chat_AdminActionSheet_BanMultiple - restrictTitle = environment.strings.Chat_AdminActionSheet_RestrictMultiple - } - title = self.isConfigurationExpanded ? restrictTitle : banTitle - } - - var accessory: ListActionItemComponent.Accessory? - if component.peers.count > 1 { - accessory = .custom(ListActionItemComponent.CustomAccessory( - component: AnyComponentWithIdentity(id: 0, component: AnyComponent(PlainButtonComponent( - content: AnyComponent(OptionSectionExpandIndicatorComponent( - theme: environment.theme, - count: selectedPeers.isEmpty ? component.peers.count : selectedPeers.count, - isExpanded: isExpanded - )), - effectAlignment: .center, - action: { [weak self] in - guard let self else { - return - } - - switch section { - case .report: - self.isOptionReportExpanded = !self.isOptionReportExpanded - case .deleteAll: - self.isOptionDeleteAllExpanded = !self.isOptionDeleteAllExpanded - case .ban: - self.isOptionBanExpanded = !self.isOptionBanExpanded - } - - self.state?.updated(transition: .spring(duration: 0.35)) - }, - animateScale: false - ))), - insets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 2.0), - isInteractive: true - )) - } - - return AnyComponentWithIdentity(id: sectionId, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, - title: AnyComponent(VStack([ - AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: title, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - ))), - ], alignment: .left, spacing: 2.0)), - leftIcon: .check(ListActionItemComponent.LeftIcon.Check( - isSelected: !selectedPeers.isEmpty, - toggle: { [weak self] in + let sheetSize = self.sheet.update( + transition: transition, + component: AnyComponent(ResizableSheetComponent( + content: AnyComponent(AdminUserActionsContentComponent( + context: component.context, + chatPeer: component.chatPeer, + peers: component.peers, + mode: component.mode, + theme: theme, + strings: environmentValue.strings, + presentationData: presentationData, + sheetState: currentState, + disableOptionsSectionAnimation: disableOptionsSectionAnimation, + toggleOptionSelection: { [weak self] section in guard let self, let component = self.component else { return } @@ -799,75 +1256,24 @@ private final class AdminUserActionsSheetComponent: Component { } self.state?.updated(transition: .spring(duration: 0.35)) - } - )), - icon: .none, - accessory: accessory, - action: { [weak self] _ in - guard let self else { - return - } - - var selectedPeers: Set - switch section { - case .report: - selectedPeers = self.optionReportSelectedPeers - case .deleteAll: - selectedPeers = self.optionDeleteAllSelectedPeers - case .ban: - selectedPeers = self.optionBanSelectedPeers - } - - if selectedPeers.isEmpty { - for peer in component.peers { - selectedPeers.insert(peer.peer.id) + }, + toggleOptionExpansion: { [weak self] section in + guard let self else { + return } - } else { - selectedPeers.removeAll() - } - - switch section { - case .report: - self.optionReportSelectedPeers = selectedPeers - case .deleteAll: - self.optionDeleteAllSelectedPeers = selectedPeers - case .ban: - self.optionBanSelectedPeers = selectedPeers - } - - self.state?.updated(transition: .spring(duration: 0.35)) - }, - highlighting: .disabled - ))) - } - - let expandedPeersItem: (OptionsSection) -> AnyComponentWithIdentity = { section in - let sectionId: AnyHashable - let selectedPeers: Set - switch section { - case .report: - sectionId = "report-peers" - selectedPeers = self.optionReportSelectedPeers - case .deleteAll: - sectionId = "delete-all-peers" - selectedPeers = self.optionDeleteAllSelectedPeers - case .ban: - sectionId = "ban-peers" - selectedPeers = self.optionBanSelectedPeers - } - - var peerItems: [AnyComponentWithIdentity] = [] - for peer in component.peers { - peerItems.append(AnyComponentWithIdentity(id: peer.peer.id, component: AnyComponent(AdminUserActionsPeerComponent( - context: component.context, - theme: environment.theme, - strings: environment.strings, - baseFontSize: presentationData.listsFontSize.baseDisplaySize, - sideInset: 0.0, - title: EnginePeer(peer.peer).displayTitle(strings: environment.strings, displayOrder: .firstLast), - peer: EnginePeer(peer.peer), - selectionState: .editing(isSelected: selectedPeers.contains(peer.peer.id)), - action: { [weak self] peer in + + switch section { + case .report: + self.isOptionReportExpanded = !self.isOptionReportExpanded + case .deleteAll: + self.isOptionDeleteAllExpanded = !self.isOptionDeleteAllExpanded + case .ban: + self.isOptionBanExpanded = !self.isOptionBanExpanded + } + + self.state?.updated(transition: .spring(duration: 0.35)) + }, + togglePeerSelection: { [weak self] section, peer in guard let self else { return } @@ -898,578 +1304,165 @@ private final class AdminUserActionsSheetComponent: Component { } self.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .easeInOut))) - } - )))) - } - return AnyComponentWithIdentity(id: sectionId, component: AnyComponent(ListSubSectionComponent( - theme: environment.theme, - leftInset: 62.0, - items: peerItems - ))) - } - - var titleString: String - switch component.mode { - case .monoforum: - if let peer = component.peers.first { - titleString = environment.strings.Monoforum_DeleteTopic_Title(EnginePeer(peer.peer).compactDisplayTitle).string - } else { - titleString = environment.strings.Common_Delete - } - case let .chat(messageCount, deleteAllMessageCount, _): - titleString = environment.strings.Chat_AdminActionSheet_DeleteTitle(Int32(messageCount)) - if let deleteAllMessageCount { - if self.optionDeleteAllSelectedPeers == Set(component.peers.map(\.peer.id)) { - titleString = environment.strings.Chat_AdminActionSheet_DeleteTitle(Int32(deleteAllMessageCount)) - } - } - case let .liveStream(messageCount, deleteAllMessageCount, _): - titleString = environment.strings.Chat_AdminActionSheet_DeleteTitle(Int32(messageCount)) - if let deleteAllMessageCount { - if self.optionDeleteAllSelectedPeers == Set(component.peers.map(\.peer.id)) { - titleString = environment.strings.Chat_AdminActionSheet_DeleteTitle(Int32(deleteAllMessageCount)) - } - } - } - - let titleSize = self.title.update( - transition: .immediate, - component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: titleString, font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)) - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - leftButtonFrame.maxX * 2.0, height: 100.0) - ) - let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: floor((54.0 - titleSize.height) * 0.5)), size: titleSize) - if let titleView = title.view { - if titleView.superview == nil { - self.navigationBarContainer.addSubview(titleView) - } - //transition.setPosition(view: titleView, position: titleFrame.center) - titleView.center = titleFrame.center - titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size) - } - - let navigationBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: 54.0)) - transition.setFrame(view: self.navigationBackgroundView, frame: navigationBackgroundFrame) - self.navigationBackgroundView.update(size: navigationBackgroundFrame.size, cornerRadius: 10.0, maskedCorners: [.layerMinXMinYCorner, .layerMaxXMinYCorner], transition: transition.containedViewLayoutTransition) - transition.setFrame(layer: self.navigationBarSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: availableSize.width, height: UIScreenPixel))) - - var optionsSectionItems: [AnyComponentWithIdentity] = [] - - for option in availableOptions { - let isOptionExpanded: Bool - switch option { - case .report: - isOptionExpanded = self.isOptionReportExpanded - case .deleteAll: - isOptionExpanded = self.isOptionDeleteAllExpanded - case .ban: - isOptionExpanded = self.isOptionBanExpanded - } - - optionsSectionItems.append(optionsItem(option)) - if isOptionExpanded { - optionsSectionItems.append(expandedPeersItem(option)) - } - } - - var optionsSectionTransition = transition - if self.previousWasConfigurationExpanded != self.isConfigurationExpanded { - self.previousWasConfigurationExpanded = self.isConfigurationExpanded - optionsSectionTransition = optionsSectionTransition.withAnimation(.none) - } - let optionsSectionSize = self.optionsSection.update( - transition: optionsSectionTransition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - style: .glass, - header: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Chat_AdminActionSheet_RestrictSectionHeader, - font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), - textColor: environment.theme.list.freeTextColor - )), - maximumNumberOfLines: 0 - )), - footer: nil, - items: optionsSectionItems, - isModal: true - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0) - ) - - let optionsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: optionsSectionSize) - if let optionsSectionView = self.optionsSection.view { - if optionsSectionView.superview == nil { - self.scrollContentView.addSubview(optionsSectionView) - self.optionsSection.parentState = state - } - transition.setFrame(view: optionsSectionView, frame: optionsSectionFrame) - } - contentHeight += optionsSectionSize.height - - let partiallyRestrictTitle: String - let fullyBanTitle: String - if component.peers.count == 1 { - partiallyRestrictTitle = environment.strings.Chat_AdminActionSheet_RestrictFooterSingle - fullyBanTitle = environment.strings.Chat_AdminActionSheet_BanFooterSingle - } else { - partiallyRestrictTitle = environment.strings.Chat_AdminActionSheet_RestrictFooterMultiple - fullyBanTitle = environment.strings.Chat_AdminActionSheet_BanFooterMultiple - } - - let optionsFooterSize = self.optionsFooter.update( - transition: transition, - component: AnyComponent(PlainButtonComponent( - content: AnyComponent(OptionsSectionFooterComponent( - theme: environment.theme, - text: self.isConfigurationExpanded ? fullyBanTitle : partiallyRestrictTitle, - fontSize: presentationData.listsFontSize.itemListBaseHeaderFontSize, - isExpanded: self.isConfigurationExpanded - )), - effectAlignment: .left, - contentInsets: UIEdgeInsets(), - action: { [weak self] in - guard let self, let component = self.component else { - return - } - self.isConfigurationExpanded = !self.isConfigurationExpanded - if self.isConfigurationExpanded && self.optionBanSelectedPeers.isEmpty { - for peer in component.peers { - self.optionBanSelectedPeers.insert(peer.peer.id) - } - } - self.state?.updated(transition: .spring(duration: 0.35)) - }, - animateAlpha: true, - animateScale: false, - animateContents: true - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) - ) - - var configSectionItems: [AnyComponentWithIdentity] = [] - - enum ConfigItem: Hashable, CaseIterable { - case sendMessages - case sendMedia - case addUsers - case pinMessages - case changeInfo - } - - if case let .channel(channel) = component.chatPeer, channel.isMonoForum { - } else if case .liveStream = component.mode { - } else { - var allConfigItems: [(ConfigItem, Bool)] = [] - if !self.allowedMediaRights.isEmpty || !self.allowedParticipantRights.isEmpty { - for configItem in ConfigItem.allCases { - let isEnabled: Bool - switch configItem { - case .sendMessages: - isEnabled = self.allowedParticipantRights.contains(.sendMessages) - case .sendMedia: - isEnabled = !self.allowedMediaRights.isEmpty - case .addUsers: - isEnabled = self.allowedParticipantRights.contains(.addMembers) - case .pinMessages: - isEnabled = self.allowedParticipantRights.contains(.pinMessages) - case .changeInfo: - isEnabled = self.allowedParticipantRights.contains(.changeInfo) - } - allConfigItems.append((configItem, isEnabled)) - } - } - - loop: for (configItem, isEnabled) in allConfigItems { - let itemTitle: AnyComponent - let itemValue: Bool - switch configItem { - case .sendMessages: - itemTitle = AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_BanUser_PermissionSendMessages, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - )) - itemValue = self.participantRights.contains(.sendMessages) - case .sendMedia: - if isEnabled { - itemTitle = AnyComponent(HStack([ - AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_BanUser_PermissionSendMedia, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - ))), - AnyComponentWithIdentity(id: 1, component: AnyComponent(MediaSectionExpandIndicatorComponent( - theme: environment.theme, - title: "\(self.mediaRights.count)/\(self.allowedMediaRights.count)", - isExpanded: self.isMediaSectionExpanded - ))) - ], spacing: 7.0)) - } else { - itemTitle = AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_BanUser_PermissionSendMedia, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - )) - } - - itemValue = !self.mediaRights.isEmpty - case .addUsers: - itemTitle = AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_BanUser_PermissionAddMembers, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - )) - itemValue = self.participantRights.contains(.addMembers) - case .pinMessages: - itemTitle = AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_EditAdmin_PermissionPinMessages, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - )) - itemValue = self.participantRights.contains(.pinMessages) - case .changeInfo: - itemTitle = AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.Channel_BanUser_PermissionChangeGroupInfo, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - )) - itemValue = self.participantRights.contains(.changeInfo) - } - - configSectionItems.append(AnyComponentWithIdentity(id: configItem, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, - title: itemTitle, - accessory: .toggle(ListActionItemComponent.Toggle( - style: isEnabled ? .icons : .lock, - isOn: itemValue, - isInteractive: isEnabled, - action: isEnabled ? { [weak self] _ in - guard let self else { - return - } - - switch configItem { - case .sendMessages: - if self.participantRights.contains(.sendMessages) { - self.participantRights.remove(.sendMessages) - } else { - self.participantRights.insert(.sendMessages) - } - case .sendMedia: - if self.mediaRights.isEmpty { - self.mediaRights = self.allowedMediaRights - } else { - self.mediaRights = [] - } - case .addUsers: - if self.participantRights.contains(.addMembers) { - self.participantRights.remove(.addMembers) - } else { - self.participantRights.insert(.addMembers) - } - case .pinMessages: - if self.participantRights.contains(.pinMessages) { - self.participantRights.remove(.pinMessages) - } else { - self.participantRights.insert(.pinMessages) - } - case .changeInfo: - if self.participantRights.contains(.changeInfo) { - self.participantRights.remove(.changeInfo) - } else { - self.participantRights.insert(.changeInfo) - } - } - self.state?.updated(transition: .spring(duration: 0.35)) - } : nil - )), - action: ((isEnabled && configItem == .sendMedia) || !isEnabled) ? { [weak self] _ in + }, + toggleConfiguration: { [weak self] in guard let self, let component = self.component else { return } - if !isEnabled { - self.environment?.controller()?.present(textAlertController(context: component.context, title: nil, text: environment.strings.GroupPermission_PermissionDisabledByDefault, actions: [ - TextAlertAction(type: .defaultAction, title: environment.strings.Common_OK, action: { - }) - ]), in: .window(.root)) + self.isConfigurationExpanded = !self.isConfigurationExpanded + if self.isConfigurationExpanded && self.optionBanSelectedPeers.isEmpty { + for peer in component.peers { + self.optionBanSelectedPeers.insert(peer.peer.id) + } + } + self.state?.updated(transition: .spring(duration: 0.35)) + }, + toggleConfigItem: { [weak self] configItem in + guard let self else { + return + } + + switch configItem { + case .sendMessages: + if self.participantRights.contains(.sendMessages) { + self.participantRights.remove(.sendMessages) + } else { + self.participantRights.insert(.sendMessages) + } + case .sendMedia: + if self.mediaRights.isEmpty { + self.mediaRights = self.allowedMediaRights + } else { + self.mediaRights = [] + } + case .addUsers: + if self.participantRights.contains(.addMembers) { + self.participantRights.remove(.addMembers) + } else { + self.participantRights.insert(.addMembers) + } + case .pinMessages: + if self.participantRights.contains(.pinMessages) { + self.participantRights.remove(.pinMessages) + } else { + self.participantRights.insert(.pinMessages) + } + case .changeInfo: + if self.participantRights.contains(.changeInfo) { + self.participantRights.remove(.changeInfo) + } else { + self.participantRights.insert(.changeInfo) + } + } + self.state?.updated(transition: .spring(duration: 0.35)) + }, + toggleMediaSectionExpansion: { [weak self] in + guard let self else { + return + } + self.isMediaSectionExpanded = !self.isMediaSectionExpanded + self.state?.updated(transition: .spring(duration: 0.35)) + }, + toggleMediaRight: { [weak self] mediaRight in + guard let self else { + return + } + + if self.mediaRights.contains(mediaRight) { + self.mediaRights.remove(mediaRight) } else { - self.isMediaSectionExpanded = !self.isMediaSectionExpanded - self.state?.updated(transition: .spring(duration: 0.35)) - } - } : nil, - highlighting: .disabled - )))) - - if isEnabled, case .sendMedia = configItem, self.isMediaSectionExpanded { - var mediaItems: [AnyComponentWithIdentity] = [] - mediaRightsLoop: for possibleMediaItem in allMediaRightItems { - if !self.allowedMediaRights.contains(possibleMediaItem) { - continue + self.mediaRights.insert(mediaRight) } - let mediaItemTitle: String - switch possibleMediaItem { - case .photos: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendPhoto - case .videos: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendVideo - case .stickersAndGifs: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendStickersAndGifs - case .music: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendMusic - case .files: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendFile - case .voiceMessages: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendVoiceMessage - case .videoMessages: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendVideoMessage - case .links: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionEmbedLinks - case .polls: - mediaItemTitle = environment.strings.Channel_BanUser_PermissionSendPolls - default: - continue mediaRightsLoop - } - - mediaItems.append(AnyComponentWithIdentity(id: possibleMediaItem, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, - title: AnyComponent(VStack([ - AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: mediaItemTitle, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 1 - ))), - ], alignment: .left, spacing: 2.0)), - leftIcon: .check(ListActionItemComponent.LeftIcon.Check( - isSelected: self.mediaRights.contains(possibleMediaItem), - toggle: { [weak self] in - guard let self else { - return - } - - if self.mediaRights.contains(possibleMediaItem) { - self.mediaRights.remove(possibleMediaItem) - } else { - self.mediaRights.insert(possibleMediaItem) - } - - self.state?.updated(transition: .spring(duration: 0.35)) - } - )), - icon: .none, - accessory: .none, - action: { [weak self] _ in - guard let self else { - return - } - - if self.mediaRights.contains(possibleMediaItem) { - self.mediaRights.remove(possibleMediaItem) - } else { - self.mediaRights.insert(possibleMediaItem) - } - - self.state?.updated(transition: .spring(duration: 0.35)) - }, - highlighting: .disabled - )))) + self.state?.updated(transition: .spring(duration: 0.35)) } - configSectionItems.append(AnyComponentWithIdentity(id: "media-sub", component: AnyComponent(ListSubSectionComponent( - theme: environment.theme, - leftInset: 0.0, - items: mediaItems - )))) - } - } - } - - let configSectionSize = self.configSection.update( - transition: transition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - header: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: component.peers.count == 1 ? environment.strings.Chat_AdminActionSheet_PermissionsSectionHeader : environment.strings.Chat_AdminActionSheet_PermissionsSectionHeaderMultiple, - font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), - textColor: environment.theme.list.freeTextColor - )), - maximumNumberOfLines: 0 )), - footer: nil, - items: configSectionItems - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0) - ) - let configSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight + 30.0), size: configSectionSize) - if let configSectionView = self.configSection.view { - if configSectionView.superview == nil { - configSectionView.clipsToBounds = true - configSectionView.layer.cornerRadius = 11.0 - self.scrollContentView.addSubview(configSectionView) - self.configSection.parentState = state - } - let effectiveConfigSectionFrame: CGRect - if self.isConfigurationExpanded { - effectiveConfigSectionFrame = configSectionFrame - } else { - effectiveConfigSectionFrame = CGRect(origin: CGPoint(x: configSectionFrame.minX, y: configSectionFrame.minY - 30.0), size: CGSize(width: configSectionFrame.width, height: 0.0)) - } - transition.setFrame(view: configSectionView, frame: effectiveConfigSectionFrame) - transition.setAlpha(view: configSectionView, alpha: self.isConfigurationExpanded ? 1.0 : 0.0) - } - - if availableOptions.contains(.ban) && !configSectionItems.isEmpty { - let optionsFooterFrame: CGRect - if self.isConfigurationExpanded { - contentHeight += 30.0 - contentHeight += configSectionSize.height - contentHeight += 7.0 - optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) - contentHeight += optionsFooterSize.height - } else { - contentHeight += 7.0 - optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) - contentHeight += optionsFooterSize.height - } - if let optionsFooterView = self.optionsFooter.view { - if optionsFooterView.superview == nil { - self.scrollContentView.addSubview(optionsFooterView) - } - transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame) - transition.setAlpha(view: optionsFooterView, alpha: 1.0) - } - } else { - if let optionsFooterView = self.optionsFooter.view { - if optionsFooterView.superview == nil { - self.scrollContentView.addSubview(optionsFooterView) - } - let optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize) - transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame) - transition.setAlpha(view: optionsFooterView, alpha: 0.0) - } - } - - contentHeight += 30.0 - - let actionButtonSize = self.actionButton.update( - transition: transition, - component: AnyComponent(ButtonComponent( - background: ButtonComponent.Background( - style: .glass, - color: environment.theme.list.itemCheckColors.fillColor, - foreground: environment.theme.list.itemCheckColors.foregroundColor, - pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), - cornerRadius: 54.0 * 0.5 + titleItem: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: adminUserActionsTitle( + strings: environmentValue.strings, + mode: component.mode, + peers: component.peers, + selectedDeleteAllPeers: self.optionDeleteAllSelectedPeers + ), + font: Font.semibold(17.0), + textColor: theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 1 + )), + leftItem: AnyComponent( + GlassBarButtonComponent( + size: CGSize(width: 44.0, height: 44.0), + backgroundColor: nil, + isDark: theme.overallDarkAppearance, + state: .glass, + component: AnyComponentWithIdentity(id: "close", component: AnyComponent( + BundleIconComponent( + name: "Navigation/Close", + tintColor: theme.chat.inputPanel.panelControlColor + ) + )), + action: { _ in + dismiss(true) + } + ) ), - content: AnyComponentWithIdentity( - id: AnyHashable(0), - component: AnyComponent(ButtonTextContentComponent( - text: environment.strings.Chat_AdminActionSheet_ActionButton, - badge: 0, - textColor: environment.theme.list.itemCheckColors.foregroundColor, - badgeBackground: environment.theme.list.itemCheckColors.foregroundColor, - badgeForeground: environment.theme.list.itemCheckColors.fillColor - )) - ), - isEnabled: true, - displaysProgress: false, - action: { [weak self] in - guard let self, let component = self.component else { - return + bottomItem: AnyComponent(ButtonComponent( + background: ButtonComponent.Background( + style: .glass, + color: theme.list.itemCheckColors.fillColor, + foreground: theme.list.itemCheckColors.foregroundColor, + pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), + cornerRadius: 54.0 * 0.5 + ), + content: AnyComponentWithIdentity( + id: AnyHashable(0), + component: AnyComponent(ButtonTextContentComponent( + text: environmentValue.strings.Chat_AdminActionSheet_ActionButton, + badge: 0, + textColor: theme.list.itemCheckColors.foregroundColor, + badgeBackground: theme.list.itemCheckColors.foregroundColor, + badgeForeground: theme.list.itemCheckColors.fillColor + )) + ), + isEnabled: true, + displaysProgress: false, + action: { + performMainAction() } - self.environment?.controller()?.dismiss() - - switch component.mode { - case let .monoforum(completion): - completion(self.calculateMonoforumResult()) - case let .chat(_, _, completion): - completion(self.calculateChatResult()) - case let .liveStream(_, _, completion): - completion(self.calculateLiveStreamResult()) - } - } + )), + backgroundColor: .color(theme.list.modalBlocksBackgroundColor), + animateOut: self.animateOut )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 54.0) + environment: { + environmentValue + ResizableSheetComponentEnvironment( + theme: theme, + statusBarHeight: environmentValue.statusBarHeight, + safeInsets: environmentValue.safeInsets, + inputHeight: 0.0, + metrics: environmentValue.metrics, + deviceMetrics: environmentValue.deviceMetrics, + isDisplaying: environmentValue.isVisible, + isCentered: environmentValue.metrics.widthClass == .regular, + screenSize: availableSize, + regularMetricsSize: nil, + dismiss: { animated in + dismiss(animated) + } + ) + }, + forceUpdate: true, + containerSize: availableSize ) - let bottomPanelHeight = 8.0 + environment.safeInsets.bottom + actionButtonSize.height - let actionButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: availableSize.height - bottomPanelHeight), size: actionButtonSize) - if let actionButtonView = actionButton.view { - if actionButtonView.superview == nil { - self.addSubview(actionButtonView) + self.sheet.parentState = state + if let sheetView = self.sheet.view { + if sheetView.superview == nil { + self.addSubview(sheetView) } - transition.setFrame(view: actionButtonView, frame: actionButtonFrame) + transition.setFrame(view: sheetView, frame: CGRect(origin: .zero, size: sheetSize)) } - contentHeight += bottomPanelHeight - - clippingY = actionButtonFrame.minY - 24.0 - - let topInset: CGFloat = max(0.0, availableSize.height - containerInset - contentHeight) - - let scrollContentHeight = max(topInset + contentHeight + containerInset, availableSize.height - containerInset) - - self.scrollContentClippingView.layer.cornerRadius = 10.0 - - self.itemLayout = ItemLayout(containerSize: availableSize, containerInset: containerInset, bottomInset: environment.safeInsets.bottom, topInset: topInset) - - transition.setFrame(view: self.scrollContentView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset + containerInset), size: CGSize(width: availableSize.width, height: contentHeight))) - - transition.setPosition(layer: self.backgroundLayer, position: CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0)) - transition.setBounds(layer: self.backgroundLayer, bounds: CGRect(origin: CGPoint(), size: availableSize)) - - let scrollClippingFrame = CGRect(origin: CGPoint(x: sideInset, y: containerInset), size: CGSize(width: availableSize.width - sideInset * 2.0, height: clippingY - containerInset)) - transition.setPosition(view: self.scrollContentClippingView, position: scrollClippingFrame.center) - transition.setBounds(view: self.scrollContentClippingView, bounds: CGRect(origin: CGPoint(x: scrollClippingFrame.minX, y: scrollClippingFrame.minY), size: scrollClippingFrame.size)) - - self.ignoreScrolling = true - let previousBounds = self.scrollView.bounds - transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: availableSize.width, height: availableSize.height))) - let contentSize = CGSize(width: availableSize.width, height: scrollContentHeight) - if contentSize != self.scrollView.contentSize { - self.scrollView.contentSize = contentSize - } - if resetScrolling { - self.scrollView.bounds = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: availableSize) - } else { - if !previousBounds.isEmpty, !transition.animation.isImmediate { - let bounds = self.scrollView.bounds - if bounds.maxY != previousBounds.maxY { - let offsetY = previousBounds.maxY - bounds.maxY - transition.animateBoundsOrigin(view: self.scrollView, from: CGPoint(x: 0.0, y: offsetY), to: CGPoint(), additive: true) - } - } - } - self.ignoreScrolling = false - self.updateScrolling(transition: transition) - return availableSize } } @@ -1488,17 +1481,20 @@ public class AdminUserActionsSheet: ViewControllerComponentContainer { case chat(messageCount: Int, deleteAllMessageCount: Int?, completion: (ChatResult) -> Void) case liveStream(messageCount: Int, deleteAllMessageCount: Int?, completion: (LiveStreamResult) -> Void) case monoforum(completion: (MonoforumResult) -> Void) + case chatReaction(completion: (ChatResult) -> Void) } public final class ChatResult { public let reportSpamPeers: [EnginePeer.Id] public let deleteAllFromPeers: [EnginePeer.Id] + public let deleteAllReactionsFromPeers: [EnginePeer.Id] public let banPeers: [EnginePeer.Id] public let updateBannedRights: [EnginePeer.Id: TelegramChatBannedRights] - init(reportSpamPeers: [EnginePeer.Id], deleteAllFromPeers: [EnginePeer.Id], banPeers: [EnginePeer.Id], updateBannedRights: [EnginePeer.Id: TelegramChatBannedRights]) { + init(reportSpamPeers: [EnginePeer.Id], deleteAllFromPeers: [EnginePeer.Id], deleteAllReactionsFromPeers: [EnginePeer.Id], banPeers: [EnginePeer.Id], updateBannedRights: [EnginePeer.Id: TelegramChatBannedRights]) { self.reportSpamPeers = reportSpamPeers self.deleteAllFromPeers = deleteAllFromPeers + self.deleteAllReactionsFromPeers = deleteAllReactionsFromPeers self.banPeers = banPeers self.updateBannedRights = updateBannedRights } @@ -1527,12 +1523,17 @@ public class AdminUserActionsSheet: ViewControllerComponentContainer { } private let context: AccountContext - private var isDismissed: Bool = false + private var dismissCompletion: (() -> Void)? public init(context: AccountContext, chatPeer: EnginePeer, peers: [RenderedChannelParticipant], mode: Mode, customTheme: PresentationTheme? = nil) { self.context = context - super.init(context: context, component: AdminUserActionsSheetComponent(context: context, chatPeer: chatPeer, peers: peers, mode: mode), navigationBarAppearance: .none, theme: customTheme.flatMap({ .custom($0) }) ?? .default) + super.init( + context: context, + component: AdminUserActionsSheetComponent(context: context, chatPeer: chatPeer, peers: peers, mode: mode), + navigationBarAppearance: .none, + theme: customTheme.flatMap({ .custom($0) }) ?? .default + ) self.statusBar.statusBarStyle = .Ignore self.navigationPresentation = .flatModal @@ -1548,24 +1549,30 @@ public class AdminUserActionsSheet: ViewControllerComponentContainer { override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - self.view.disablesInteractiveModalDismiss = true - - if let componentView = self.node.hostView.componentView as? AdminUserActionsSheetComponent.View { - componentView.animateIn() + } + + fileprivate func completePendingDismiss() { + let dismissCompletion = self.dismissCompletion + self.dismissCompletion = nil + dismissCompletion?() + } + + public func dismissAnimated() { + if let view = self.node.hostView.findTaggedView(tag: ResizableSheetComponent.View.Tag()) as? ResizableSheetComponent.View { + view.dismissAnimated() } } override public func dismiss(completion: (() -> Void)? = nil) { if !self.isDismissed { self.isDismissed = true + self.dismissCompletion = completion - if let componentView = self.node.hostView.componentView as? AdminUserActionsSheetComponent.View { - componentView.animateOut(completion: { [weak self] in - completion?() - self?.dismiss(animated: false) - }) + if let view = self.node.hostView.findTaggedView(tag: ResizableSheetComponent.View.Tag()) as? ResizableSheetComponent.View { + view.dismissAnimated() } else { + self.completePendingDismiss() self.dismiss(animated: false) } } diff --git a/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift b/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift index 542ac3ba4c..2b28a3c333 100644 --- a/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift +++ b/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift @@ -465,7 +465,7 @@ public final class ButtonComponent: Component { private var glassShadowCornerRadius: CGFloat? private var glassHighlightContainerView: UIView? private let button: HighlightTrackingButton - private let legacyGlassHighlightRecognizer: GlassHighlightGestureRecognizer + private let glassHighlightRecognizer: GlassHighlightGestureRecognizer private var shimmeringView: ButtonShimmeringView? private var chromeView: UIImageView? @@ -480,7 +480,7 @@ public final class ButtonComponent: Component { self.containerView.isUserInteractionEnabled = false self.button = HighlightTrackingButton() - self.legacyGlassHighlightRecognizer = GlassHighlightGestureRecognizer(target: nil, action: nil) + self.glassHighlightRecognizer = GlassHighlightGestureRecognizer(target: nil, action: nil) super.init(frame: frame) @@ -489,8 +489,8 @@ public final class ButtonComponent: Component { self.addSubview(self.containerView) self.addSubview(self.button) - self.addGestureRecognizer(self.legacyGlassHighlightRecognizer) - self.legacyGlassHighlightRecognizer.isEnabled = false + self.addGestureRecognizer(self.glassHighlightRecognizer) + self.glassHighlightRecognizer.isEnabled = false self.button.addTarget(self, action: #selector(self.pressed), for: .touchUpInside) @@ -521,33 +521,18 @@ public final class ButtonComponent: Component { preconditionFailure() } - private func ensureGlassShadowView() -> UIImageView { - if let glassShadowView = self.glassShadowView { - return glassShadowView - } - let glassShadowView = UIImageView() - glassShadowView.isUserInteractionEnabled = false - self.glassShadowView = glassShadowView - return glassShadowView - } - - private func ensureGlassHighlightContainerView() -> UIView { - if let glassHighlightContainerView = self.glassHighlightContainerView { - return glassHighlightContainerView - } - let glassHighlightContainerView = UIView() - glassHighlightContainerView.isUserInteractionEnabled = false - glassHighlightContainerView.clipsToBounds = true - self.glassHighlightContainerView = glassHighlightContainerView - return glassHighlightContainerView - } - - private func removeLegacyGlassEffectViews() { - self.legacyGlassHighlightRecognizer.isEnabled = false - self.legacyGlassHighlightRecognizer.highlightContainerView = nil + private func removeGlassEffect(transition: ComponentTransition) { + self.glassHighlightRecognizer.isEnabled = false + self.glassHighlightRecognizer.highlightContainerView = nil if let glassShadowView = self.glassShadowView, glassShadowView.superview != nil { - glassShadowView.removeFromSuperview() + if transition.animation.isImmediate { + glassShadowView.removeFromSuperview() + } else { + transition.setAlpha(view: glassShadowView, alpha: 0.0, completion: { _ in + glassShadowView.removeFromSuperview() + }) + } } if let glassHighlightContainerView = self.glassHighlightContainerView, glassHighlightContainerView.superview != nil { glassHighlightContainerView.removeFromSuperview() @@ -558,10 +543,17 @@ public final class ButtonComponent: Component { self.layer.sublayerTransform = CATransform3DIdentity } - private func updateLegacyGlassEffectViews(component: ButtonComponent, size: CGSize, cornerRadius: CGFloat, transition: ComponentTransition) { + private func updateGlassEffect(component: ButtonComponent, size: CGSize, cornerRadius: CGFloat, transition: ComponentTransition) { let shadowInset: CGFloat = 48.0 - let glassShadowView = self.ensureGlassShadowView() + let glassShadowView: UIImageView + if let current = self.glassShadowView { + glassShadowView = current + } else { + glassShadowView = UIImageView() + glassShadowView.isUserInteractionEnabled = false + self.glassShadowView = glassShadowView + } if glassShadowView.superview == nil { self.insertSubview(glassShadowView, at: 0) } else { @@ -574,7 +566,15 @@ public final class ButtonComponent: Component { transition.setFrame(view: glassShadowView, frame: CGRect(origin: .zero, size: size).insetBy(dx: -shadowInset, dy: -shadowInset)) transition.setAlpha(view: glassShadowView, alpha: 1.0) - let glassHighlightContainerView = self.ensureGlassHighlightContainerView() + let glassHighlightContainerView: UIView + if let current = self.glassHighlightContainerView { + glassHighlightContainerView = current + } else { + glassHighlightContainerView = UIView() + glassHighlightContainerView.isUserInteractionEnabled = false + glassHighlightContainerView.clipsToBounds = true + self.glassHighlightContainerView = glassHighlightContainerView + } if glassHighlightContainerView.superview == nil { self.insertSubview(glassHighlightContainerView, aboveSubview: self.containerView) } else if self.button.superview === self { @@ -585,8 +585,8 @@ public final class ButtonComponent: Component { transition.setFrame(view: glassHighlightContainerView, frame: CGRect(origin: .zero, size: size)) transition.setCornerRadius(layer: glassHighlightContainerView.layer, cornerRadius: cornerRadius) - self.legacyGlassHighlightRecognizer.highlightContainerView = glassHighlightContainerView - self.legacyGlassHighlightRecognizer.isEnabled = component.isEnabled && !component.displaysProgress + self.glassHighlightRecognizer.highlightContainerView = glassHighlightContainerView + self.glassHighlightRecognizer.isEnabled = component.isEnabled && !component.displaysProgress } @objc private func pressed() { @@ -694,10 +694,10 @@ public final class ButtonComponent: Component { transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: cornerRadius) } - if component.background.style == .glass { - self.updateLegacyGlassEffectViews(component: component, size: size, cornerRadius: cornerRadius, transition: transition) + if component.background.style == .glass, component.background.color.alpha > 1.0 - .ulpOfOne { + self.updateGlassEffect(component: component, size: size, cornerRadius: cornerRadius, transition: transition) } else { - self.removeLegacyGlassEffectViews() + self.removeGlassEffect(transition: transition) } if let contentView = contentItem.view.view { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift index d3dbc8ef0b..dc1f534a6f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift @@ -2684,8 +2684,9 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { var pollOptionsFinalizeLayouts: [(hasResult: Bool, layout: (CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode))] = [] var addOptionFinalizeLayout: ((CGFloat) -> (CGSize, (Bool, Bool) -> ChatMessagePollAddOptionNode))? var orderedPollOptions: [(Int, TelegramMediaPollOption)] = [] + + var isRestricted = false if let poll = poll { - var isRestricted = false if !poll.countries.isEmpty, let accountCountry = item.associatedData.accountCountry, !poll.countries.contains(accountCountry) { isRestricted = true } @@ -2842,430 +2843,428 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { let buttonViewResultsTextFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonViewResultsTextLayout.size.width) / 2.0), y: optionsButtonSpacing), size: buttonViewResultsTextLayout.size) return (resultSize, { [weak self] animation, synchronousLoad, _ in - if let strongSelf = self { - strongSelf.item = item - strongSelf.poll = poll - - let cachedLayout = strongSelf.textNode.textNode.cachedLayout - if case .System = animation { - if let cachedLayout = cachedLayout { - if !cachedLayout.areLinesEqual(to: textLayout) { - if let textContents = strongSelf.textNode.textNode.contents { - let fadeNode = ASDisplayNode() - fadeNode.displaysAsynchronously = false - fadeNode.contents = textContents - fadeNode.frame = strongSelf.textNode.textNode.frame - fadeNode.isLayerBacked = true - strongSelf.addSubnode(fadeNode) - fadeNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak fadeNode] _ in - fadeNode?.removeFromSupernode() - }) - strongSelf.textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) - } + if let strongSelf = self { + strongSelf.item = item + strongSelf.poll = poll + + let cachedLayout = strongSelf.textNode.textNode.cachedLayout + if case .System = animation { + if let cachedLayout = cachedLayout { + if !cachedLayout.areLinesEqual(to: textLayout) { + if let textContents = strongSelf.textNode.textNode.contents { + let fadeNode = ASDisplayNode() + fadeNode.displaysAsynchronously = false + fadeNode.contents = textContents + fadeNode.frame = strongSelf.textNode.textNode.frame + fadeNode.isLayerBacked = true + strongSelf.addSubnode(fadeNode) + fadeNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak fadeNode] _ in + fadeNode?.removeFromSupernode() + }) + strongSelf.textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) } } } - - let _ = textApply(TextNodeWithEntities.Arguments( - context: item.context, - cache: item.context.animationCache, - renderer: item.context.animationRenderer, - placeholderColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : item.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, - attemptSynchronous: synchronousLoad) - ) - let _ = typeApply() - - var verticalOffset = textFrame.maxY + titleTypeSpacing + typeLayout.size.height + typeOptionsSpacing - var updatedOptionNodes: [ChatMessagePollOptionNode] = [] - for i in 0 ..< optionNodesSizesAndApply.count { - let (size, apply) = optionNodesSizesAndApply[i] - var isRequesting = false - if i < orderedPollOptions.count { - if let inProgressOpaqueIds = item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] { - isRequesting = inProgressOpaqueIds.contains(orderedPollOptions[i].1.opaqueIdentifier) - } + } + + let _ = textApply(TextNodeWithEntities.Arguments( + context: item.context, + cache: item.context.animationCache, + renderer: item.context.animationRenderer, + placeholderColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : item.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, + attemptSynchronous: synchronousLoad) + ) + let _ = typeApply() + + var verticalOffset = textFrame.maxY + titleTypeSpacing + typeLayout.size.height + typeOptionsSpacing + var updatedOptionNodes: [ChatMessagePollOptionNode] = [] + for i in 0 ..< optionNodesSizesAndApply.count { + let (size, apply) = optionNodesSizesAndApply[i] + var isRequesting = false + if i < orderedPollOptions.count { + if let inProgressOpaqueIds = item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] { + isRequesting = inProgressOpaqueIds.contains(orderedPollOptions[i].1.opaqueIdentifier) } - let optionNode = apply(animation.isAnimated, isRequesting, synchronousLoad) - let optionNodeFrame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) - if optionNode.supernode !== strongSelf { - strongSelf.addSubnode(optionNode) - let option = optionNode.option - - optionNode.pressed = { [weak self] in - guard let self, - let item = self.item, - let option else { - return - } - item.controllerInteraction.requestSelectMessagePollOptions(item.message.id, [option.opaqueIdentifier]) + } + let optionNode = apply(animation.isAnimated, isRequesting, synchronousLoad) + let optionNodeFrame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) + if optionNode.supernode !== strongSelf { + strongSelf.addSubnode(optionNode) + let option = optionNode.option + + optionNode.pressed = { [weak self] in + guard let self, + let item = self.item, + let option else { + return } - optionNode.resultPressed = { [weak self] in - guard let self, - let item = self.item, - let option else { - return - } - if let poll { - if case .public = poll.publicity { - item.controllerInteraction.openMessagePollResults(item.message.id, option.opaqueIdentifier) - } else { - if "".isEmpty { - let locale = localeWithStrings(item.presentationData.strings) - let countryNames = poll.countries.map { id in - if let countryName = locale.localizedString(forRegionCode: id) { - return countryName - } else { - return id - } - } - var countries: String = "" - if countryNames.count == 1, let country = countryNames.first { - countries = "**\(country)**" - } else { - for i in 0 ..< countryNames.count { - countries.append("**\(countryNames[i])**") - if i == countryNames.count - 2 { - countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesLastDelimiter) - } else if i < countryNames.count - 2 { - countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesDelimiter) - } - } - } - //TODO:localize - let controller = UndoOverlayController( - presentationData: item.context.sharedContext.currentPresentationData.with { $0 }, - content: .banned(text: "Only users from \(countries) can vote."), - elevatedLayout: true, - position: .bottom, - action: { _ in return true } - ) - item.controllerInteraction.presentController(controller, nil) + item.controllerInteraction.requestSelectMessagePollOptions(item.message.id, [option.opaqueIdentifier]) + } + optionNode.resultPressed = { [weak self] in + guard let self, + let item = self.item, + let option else { + return + } + if let poll { + if case .public = poll.publicity { + item.controllerInteraction.openMessagePollResults(item.message.id, option.opaqueIdentifier) + } else if isRestricted { + let locale = localeWithStrings(item.presentationData.strings) + let countryNames = poll.countries.map { id in + if let countryName = locale.localizedString(forRegionCode: id) { + return countryName + } else { + return id } } + var countries: String = "" + if countryNames.count == 1, let country = countryNames.first { + countries = "**\(country)**" + } else { + for i in 0 ..< countryNames.count { + countries.append("**\(countryNames[i])**") + if i == countryNames.count - 2 { + countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesLastDelimiter) + } else if i < countryNames.count - 2 { + countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesDelimiter) + } + } + } + //TODO:localize + let controller = UndoOverlayController( + presentationData: item.context.sharedContext.currentPresentationData.with { $0 }, + content: .banned(text: "Only users from \(countries) can vote."), + elevatedLayout: true, + position: .bottom, + action: { _ in return true } + ) + item.controllerInteraction.presentController(controller, nil) } } - optionNode.selectionUpdated = { [weak self] in - guard let self else { - return - } - self.updateSelection() - } - optionNode.longTapped = { [weak self] in - guard let self, - let item = self.item, - let option else { - return - } - item.controllerInteraction.pollOptionLongTap(option.opaqueIdentifier, ChatControllerInteraction.LongTapParams(message: item.message, contentNode: optionNode.contextSourceNode, messageNode: strongSelf, progress: nil)) - } - optionNode.frame = optionNodeFrame - } else { - animation.animator.updateFrame(layer: optionNode.layer, frame: optionNodeFrame, completion: nil) } - - if optionNode.currentResult != nil { - verticalOffset += size.height - 7.0 - } else { - verticalOffset += size.height - } - updatedOptionNodes.append(optionNode) - optionNode.isUserInteractionEnabled = !strongSelf.newOptionIsFocused && item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] == nil - optionNode.alpha = strongSelf.newOptionIsFocused ? 0.5 : 1.0 - - if i > 0 { - optionNode.previousOptionNode = updatedOptionNodes[i - 1] - } else { - optionNode.previousOptionNode = nil - } - } - for optionNode in strongSelf.optionNodes { - if !updatedOptionNodes.contains(where: { $0 === optionNode }) { - optionNode.removeFromSupernode() - } - } - strongSelf.optionNodes = updatedOptionNodes - strongSelf.updatePollOptionsInteraction(animated: animation.isAnimated) - - if let (size, apply) = addOptionSizeAndApply { - let isRequesting = item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] != nil - let addOptionNode = apply(animation.isAnimated, isRequesting) - let addOptionNodeFrame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) - if addOptionNode.supernode !== strongSelf { - strongSelf.addSubnode(addOptionNode) - } else { - animation.animator.updateFrame(layer: addOptionNode.layer, frame: addOptionNodeFrame, completion: nil) - } - addOptionNode.frame = addOptionNodeFrame - addOptionNode.isUserInteractionEnabled = !isRequesting - addOptionNode.textUpdated = { [weak self] text in - self?.updateNewOptionText(text) - } - addOptionNode.heightUpdated = { [weak self] in - self?.requestNewOptionLayoutUpdate() - } - addOptionNode.attachPressed = { [weak self] in - self?.openNewOptionAttachment() - } - addOptionNode.mediaPressed = { [weak self] in - self?.openNewOptionAttachment() - } - addOptionNode.modeSelectorPressed = { [weak self] in - self?.toggleNewOptionInputMode() - } - addOptionNode.requestSave = { [weak self] in - self?.buttonPressed() - } - addOptionNode.focusUpdated = { [weak self] focused in + optionNode.selectionUpdated = { [weak self] in guard let self else { return } - self.updatePollAddOptionFocused(focused) + self.updateSelection() } - strongSelf.addOptionNode = addOptionNode + optionNode.longTapped = { [weak self] in + guard let self, + let item = self.item, + let option else { + return + } + item.controllerInteraction.pollOptionLongTap(option.opaqueIdentifier, ChatControllerInteraction.LongTapParams(message: item.message, contentNode: optionNode.contextSourceNode, messageNode: strongSelf, progress: nil)) + } + optionNode.frame = optionNodeFrame + } else { + animation.animator.updateFrame(layer: optionNode.layer, frame: optionNodeFrame, completion: nil) + } + + if optionNode.currentResult != nil { + verticalOffset += size.height - 7.0 + } else { verticalOffset += size.height - } else if let addOptionNode = strongSelf.addOptionNode { - strongSelf.updatePollAddOptionFocused(false) - strongSelf.addOptionNode = nil - addOptionNode.removeFromSupernode() } + updatedOptionNodes.append(optionNode) + optionNode.isUserInteractionEnabled = !strongSelf.newOptionIsFocused && item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] == nil + optionNode.alpha = strongSelf.newOptionIsFocused ? 0.5 : 1.0 - if let poll = poll, let pendingNewOptionSubmissionText, let pendingNewOptionOptionCount = strongSelf.pendingNewOptionOptionCount, poll.options.count > pendingNewOptionOptionCount, poll.options.contains(where: { $0.text == pendingNewOptionSubmissionText }) { - strongSelf.clearNewOptionInput() - } - - if textLayout.hasRTL { - strongSelf.textNode.textNode.frame = CGRect(origin: CGPoint(x: resultSize.width - textFrame.size.width - textInsets.left - layoutConstants.text.bubbleInsets.right - additionalTextRightInset, y: textFrame.origin.y), size: textFrame.size) + if i > 0 { + optionNode.previousOptionNode = updatedOptionNodes[i - 1] } else { - strongSelf.textNode.textNode.frame = textFrame + optionNode.previousOptionNode = nil } - let typeFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: textFrame.maxY + titleTypeSpacing), size: typeLayout.size) - animation.animator.updateFrame(layer: strongSelf.typeNode.layer, frame: typeFrame, completion: nil) - - let deadlineTimeout = poll?.deadlineTimeout - var displayDeadlineTimer = true - var hasSelected = false - - if let poll { - if let voters = poll.results.voters { - for voter in voters { - if voter.selected { - if case .quiz = poll.kind { - displayDeadlineTimer = false - } else { - displayDeadlineTimer = !poll.isClosed - } - hasSelected = true - break - } - } - } - } - - var endDate: Int32? - if let deadlineTimeout, - message.id.namespace == Namespaces.Message.Cloud { - let startDate: Int32 - if let forwardInfo = message.forwardInfo { - startDate = forwardInfo.date - } else { - startDate = message.timestamp - } - endDate = startDate + deadlineTimeout - } - - if let poll, case .quiz = poll.kind, let deadlineTimeout, !isClosed { - let timerNode: PollBubbleTimerNode - if let current = strongSelf.timerNode { - timerNode = current - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - if displayDeadlineTimer { - timerTransition.updateAlpha(node: timerNode, alpha: 1.0) - } else { - timerTransition.updateAlpha(node: timerNode, alpha: 0.0) - } - } else { - timerNode = PollBubbleTimerNode() - strongSelf.timerNode = timerNode - strongSelf.addSubnode(timerNode) - timerNode.reachedTimeout = { - guard let strongSelf = self, - let _ = strongSelf.item else { - return - } - //item.controllerInteraction.requestMessageUpdate(item.message.id) - } - - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - if displayDeadlineTimer { - timerNode.alpha = 0.0 - timerTransition.updateAlpha(node: timerNode, alpha: 1.0) - } else { - timerNode.alpha = 0.0 - } - } - timerNode.update(regularColor: messageTheme.secondaryTextColor, proximityColor: messageTheme.scamColor, timeout: deadlineTimeout, deadlineTimestamp: endDate) - timerNode.frame = CGRect(origin: CGPoint(x: resultSize.width - layoutConstants.text.bubbleInsets.right, y: typeFrame.minY), size: CGSize()) - } else if let timerNode = strongSelf.timerNode { - strongSelf.timerNode = nil - - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - timerTransition.updateAlpha(node: timerNode, alpha: 0.0, completion: { [weak timerNode] _ in - timerNode?.removeFromSupernode() - }) - timerTransition.updateTransformScale(node: timerNode, scale: 0.1) - } - - var statusOffset: CGFloat = 0.0 - if let poll, case .poll = poll.kind, let endDate, !isClosed { - let timerNode: DeadlineTimerNode - if let current = strongSelf.deadlineTimerNode { - timerNode = current - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - if displayDeadlineTimer { - timerTransition.updateAlpha(node: timerNode, alpha: 1.0) - } else { - timerTransition.updateAlpha(node: timerNode, alpha: 0.0) - } - } else { - timerNode = DeadlineTimerNode() - strongSelf.deadlineTimerNode = timerNode - strongSelf.addSubnode(timerNode) - - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - if displayDeadlineTimer { - timerNode.alpha = 0.0 - timerTransition.updateAlpha(node: timerNode, alpha: 1.0) - } else { - timerNode.alpha = 0.0 - } - } - timerNode.update(size: resultSize, color: messageTheme.secondaryTextColor, deadlineTimeout: endDate, resultsHidden: poll.hideResultsUntilClose, strings: item.presentationData.strings) - timerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: verticalOffset + 31.0), size: CGSize(width: resultSize.width, height: 20.0)) - statusOffset += 6.0 - } else if let timerNode = strongSelf.deadlineTimerNode { - strongSelf.deadlineTimerNode = nil - - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - timerTransition.updateAlpha(node: timerNode, alpha: 0.0, completion: { [weak timerNode] _ in - timerNode?.removeFromSupernode() - }) - timerTransition.updateTransformScale(node: timerNode, scale: 0.1) - } - - let solutionButtonSize = CGSize(width: 32.0, height: 32.0) - let solutionButtonFrame = CGRect(origin: CGPoint(x: resultSize.width - layoutConstants.text.bubbleInsets.right - solutionButtonSize.width + 5.0, y: typeFrame.minY - 16.0), size: solutionButtonSize) - strongSelf.solutionButtonNode.frame = solutionButtonFrame - - if (strongSelf.timerNode == nil || !displayDeadlineTimer), let poll = poll, case .quiz = poll.kind, let _ = poll.results.solution, (isClosed || hasSelected) { - if strongSelf.solutionButtonNode.alpha.isZero { - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - timerTransition.updateAlpha(node: strongSelf.solutionButtonNode, alpha: 1.0) - } - strongSelf.solutionButtonNode.update(size: solutionButtonSize, theme: item.presentationData.theme.theme, incoming: incoming) - } else if !strongSelf.solutionButtonNode.alpha.isZero { - let timerTransition: ContainedViewLayoutTransition - if animation.isAnimated { - timerTransition = .animated(duration: 0.25, curve: .easeInOut) - } else { - timerTransition = .immediate - } - timerTransition.updateAlpha(node: strongSelf.solutionButtonNode, alpha: 0.0) - } - - let avatarsFrame = CGRect(origin: CGPoint(x: typeFrame.maxX + 6.0, y: typeFrame.minY + floor((typeFrame.height - MergedAvatarsNode.defaultMergedImageSize) / 2.0)), size: CGSize(width: MergedAvatarsNode.defaultMergedImageSize + MergedAvatarsNode.defaultMergedImageSpacing * 2.0, height: MergedAvatarsNode.defaultMergedImageSize)) - strongSelf.avatarsNode.frame = avatarsFrame - strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size) - strongSelf.avatarsNode.update(context: item.context, peers: avatarPeers, synchronousLoad: synchronousLoad, imageSize: MergedAvatarsNode.defaultMergedImageSize, imageSpacing: MergedAvatarsNode.defaultMergedImageSpacing, borderWidth: MergedAvatarsNode.defaultBorderWidth) - strongSelf.avatarsNode.isHidden = isBotChat - let alphaTransition: ContainedViewLayoutTransition - if animation.isAnimated { - alphaTransition = .animated(duration: 0.25, curve: .easeInOut) - alphaTransition.updateAlpha(node: strongSelf.avatarsNode, alpha: avatarPeers.isEmpty ? 0.0 : 1.0) - } else { - alphaTransition = .immediate - } - - let _ = votersApply() - let votersFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - votersLayout.size.width) / 2.0), y: verticalOffset + optionsVotersSpacing), size: votersLayout.size) - animation.animator.updateFrame(layer: strongSelf.votersNode.layer, frame: votersFrame, completion: nil) - - if animation.isAnimated, let previousPoll = previousPoll, let poll = poll { - if previousPoll.results.totalVoters == nil && poll.results.totalVoters != nil { - strongSelf.votersNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) - } - } - - if let statusSizeAndApply = statusSizeAndApply { - let statusFrame = CGRect(origin: CGPoint(x: resultSize.width - statusSizeAndApply.0.width - layoutConstants.text.bubbleInsets.right, y: votersFrame.maxY + statusOffset), size: statusSizeAndApply.0) - - if strongSelf.statusNode.supernode == nil { - statusSizeAndApply.1(.None) - strongSelf.statusNode.frame = statusFrame - strongSelf.addSubnode(strongSelf.statusNode) - } else { - statusSizeAndApply.1(animation) - animation.animator.updateFrame(layer: strongSelf.statusNode.layer, frame: statusFrame, completion: nil) - } - } else if strongSelf.statusNode.supernode != nil { - strongSelf.statusNode.removeFromSupernode() - } - - let _ = buttonSubmitInactiveTextApply() - strongSelf.buttonSubmitInactiveTextNode.frame = buttonSubmitInactiveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) - - let _ = buttonSubmitActiveTextApply() - strongSelf.buttonSubmitActiveTextNode.frame = buttonSubmitActiveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) - - let _ = buttonSaveTextApply() - strongSelf.buttonSaveTextNode.frame = buttonSaveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) - - let _ = buttonViewResultsTextApply() - strongSelf.buttonViewResultsTextNode.frame = buttonViewResultsTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) - - strongSelf.updateSelection() - strongSelf.updatePollTooltipMessageState(animated: false) - - let buttonWidth: CGFloat = floor(max(strongSelf.buttonSaveTextNode.frame.width, max(strongSelf.buttonViewResultsTextNode.frame.width, strongSelf.buttonSubmitActiveTextNode.frame.width)) * 1.1) - strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonWidth) / 2.0), y: verticalOffset), size: CGSize(width: buttonWidth, height: 44.0)) - - strongSelf.updateIsTranslating(isTranslating) } - }) + for optionNode in strongSelf.optionNodes { + if !updatedOptionNodes.contains(where: { $0 === optionNode }) { + optionNode.removeFromSupernode() + } + } + strongSelf.optionNodes = updatedOptionNodes + strongSelf.updatePollOptionsInteraction(animated: animation.isAnimated) + + if let (size, apply) = addOptionSizeAndApply { + let isRequesting = item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] != nil + let addOptionNode = apply(animation.isAnimated, isRequesting) + let addOptionNodeFrame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) + if addOptionNode.supernode !== strongSelf { + strongSelf.addSubnode(addOptionNode) + } else { + animation.animator.updateFrame(layer: addOptionNode.layer, frame: addOptionNodeFrame, completion: nil) + } + addOptionNode.frame = addOptionNodeFrame + addOptionNode.isUserInteractionEnabled = !isRequesting + addOptionNode.textUpdated = { [weak self] text in + self?.updateNewOptionText(text) + } + addOptionNode.heightUpdated = { [weak self] in + self?.requestNewOptionLayoutUpdate() + } + addOptionNode.attachPressed = { [weak self] in + self?.openNewOptionAttachment() + } + addOptionNode.mediaPressed = { [weak self] in + self?.openNewOptionAttachment() + } + addOptionNode.modeSelectorPressed = { [weak self] in + self?.toggleNewOptionInputMode() + } + addOptionNode.requestSave = { [weak self] in + self?.buttonPressed() + } + addOptionNode.focusUpdated = { [weak self] focused in + guard let self else { + return + } + self.updatePollAddOptionFocused(focused) + } + strongSelf.addOptionNode = addOptionNode + verticalOffset += size.height + } else if let addOptionNode = strongSelf.addOptionNode { + strongSelf.updatePollAddOptionFocused(false) + strongSelf.addOptionNode = nil + addOptionNode.removeFromSupernode() + } + + if let poll = poll, let pendingNewOptionSubmissionText, let pendingNewOptionOptionCount = strongSelf.pendingNewOptionOptionCount, poll.options.count > pendingNewOptionOptionCount, poll.options.contains(where: { $0.text == pendingNewOptionSubmissionText }) { + strongSelf.clearNewOptionInput() + } + + if textLayout.hasRTL { + strongSelf.textNode.textNode.frame = CGRect(origin: CGPoint(x: resultSize.width - textFrame.size.width - textInsets.left - layoutConstants.text.bubbleInsets.right - additionalTextRightInset, y: textFrame.origin.y), size: textFrame.size) + } else { + strongSelf.textNode.textNode.frame = textFrame + } + let typeFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: textFrame.maxY + titleTypeSpacing), size: typeLayout.size) + animation.animator.updateFrame(layer: strongSelf.typeNode.layer, frame: typeFrame, completion: nil) + + let deadlineTimeout = poll?.deadlineTimeout + var displayDeadlineTimer = true + var hasSelected = false + + if let poll { + if let voters = poll.results.voters { + for voter in voters { + if voter.selected { + if case .quiz = poll.kind { + displayDeadlineTimer = false + } else { + displayDeadlineTimer = !poll.isClosed + } + hasSelected = true + break + } + } + } + } + + var endDate: Int32? + if let deadlineTimeout, + message.id.namespace == Namespaces.Message.Cloud { + let startDate: Int32 + if let forwardInfo = message.forwardInfo { + startDate = forwardInfo.date + } else { + startDate = message.timestamp + } + endDate = startDate + deadlineTimeout + } + + if let poll, case .quiz = poll.kind, let deadlineTimeout, !isClosed { + let timerNode: PollBubbleTimerNode + if let current = strongSelf.timerNode { + timerNode = current + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + if displayDeadlineTimer { + timerTransition.updateAlpha(node: timerNode, alpha: 1.0) + } else { + timerTransition.updateAlpha(node: timerNode, alpha: 0.0) + } + } else { + timerNode = PollBubbleTimerNode() + strongSelf.timerNode = timerNode + strongSelf.addSubnode(timerNode) + timerNode.reachedTimeout = { + guard let strongSelf = self, + let _ = strongSelf.item else { + return + } + //item.controllerInteraction.requestMessageUpdate(item.message.id) + } + + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + if displayDeadlineTimer { + timerNode.alpha = 0.0 + timerTransition.updateAlpha(node: timerNode, alpha: 1.0) + } else { + timerNode.alpha = 0.0 + } + } + timerNode.update(regularColor: messageTheme.secondaryTextColor, proximityColor: messageTheme.scamColor, timeout: deadlineTimeout, deadlineTimestamp: endDate) + timerNode.frame = CGRect(origin: CGPoint(x: resultSize.width - layoutConstants.text.bubbleInsets.right, y: typeFrame.minY), size: CGSize()) + } else if let timerNode = strongSelf.timerNode { + strongSelf.timerNode = nil + + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + timerTransition.updateAlpha(node: timerNode, alpha: 0.0, completion: { [weak timerNode] _ in + timerNode?.removeFromSupernode() + }) + timerTransition.updateTransformScale(node: timerNode, scale: 0.1) + } + + var statusOffset: CGFloat = 0.0 + if let poll, case .poll = poll.kind, let endDate, !isClosed { + let timerNode: DeadlineTimerNode + if let current = strongSelf.deadlineTimerNode { + timerNode = current + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + if displayDeadlineTimer { + timerTransition.updateAlpha(node: timerNode, alpha: 1.0) + } else { + timerTransition.updateAlpha(node: timerNode, alpha: 0.0) + } + } else { + timerNode = DeadlineTimerNode() + strongSelf.deadlineTimerNode = timerNode + strongSelf.addSubnode(timerNode) + + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + if displayDeadlineTimer { + timerNode.alpha = 0.0 + timerTransition.updateAlpha(node: timerNode, alpha: 1.0) + } else { + timerNode.alpha = 0.0 + } + } + timerNode.update(size: resultSize, color: messageTheme.secondaryTextColor, deadlineTimeout: endDate, resultsHidden: poll.hideResultsUntilClose, strings: item.presentationData.strings) + timerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: verticalOffset + 31.0), size: CGSize(width: resultSize.width, height: 20.0)) + statusOffset += 6.0 + } else if let timerNode = strongSelf.deadlineTimerNode { + strongSelf.deadlineTimerNode = nil + + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + timerTransition.updateAlpha(node: timerNode, alpha: 0.0, completion: { [weak timerNode] _ in + timerNode?.removeFromSupernode() + }) + timerTransition.updateTransformScale(node: timerNode, scale: 0.1) + } + + let solutionButtonSize = CGSize(width: 32.0, height: 32.0) + let solutionButtonFrame = CGRect(origin: CGPoint(x: resultSize.width - layoutConstants.text.bubbleInsets.right - solutionButtonSize.width + 5.0, y: typeFrame.minY - 16.0), size: solutionButtonSize) + strongSelf.solutionButtonNode.frame = solutionButtonFrame + + if (strongSelf.timerNode == nil || !displayDeadlineTimer), let poll = poll, case .quiz = poll.kind, let _ = poll.results.solution, (isClosed || hasSelected) { + if strongSelf.solutionButtonNode.alpha.isZero { + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + timerTransition.updateAlpha(node: strongSelf.solutionButtonNode, alpha: 1.0) + } + strongSelf.solutionButtonNode.update(size: solutionButtonSize, theme: item.presentationData.theme.theme, incoming: incoming) + } else if !strongSelf.solutionButtonNode.alpha.isZero { + let timerTransition: ContainedViewLayoutTransition + if animation.isAnimated { + timerTransition = .animated(duration: 0.25, curve: .easeInOut) + } else { + timerTransition = .immediate + } + timerTransition.updateAlpha(node: strongSelf.solutionButtonNode, alpha: 0.0) + } + + let avatarsFrame = CGRect(origin: CGPoint(x: typeFrame.maxX + 6.0, y: typeFrame.minY + floor((typeFrame.height - MergedAvatarsNode.defaultMergedImageSize) / 2.0)), size: CGSize(width: MergedAvatarsNode.defaultMergedImageSize + MergedAvatarsNode.defaultMergedImageSpacing * 2.0, height: MergedAvatarsNode.defaultMergedImageSize)) + strongSelf.avatarsNode.frame = avatarsFrame + strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size) + strongSelf.avatarsNode.update(context: item.context, peers: avatarPeers, synchronousLoad: synchronousLoad, imageSize: MergedAvatarsNode.defaultMergedImageSize, imageSpacing: MergedAvatarsNode.defaultMergedImageSpacing, borderWidth: MergedAvatarsNode.defaultBorderWidth) + strongSelf.avatarsNode.isHidden = isBotChat + let alphaTransition: ContainedViewLayoutTransition + if animation.isAnimated { + alphaTransition = .animated(duration: 0.25, curve: .easeInOut) + alphaTransition.updateAlpha(node: strongSelf.avatarsNode, alpha: avatarPeers.isEmpty ? 0.0 : 1.0) + } else { + alphaTransition = .immediate + } + + let _ = votersApply() + let votersFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - votersLayout.size.width) / 2.0), y: verticalOffset + optionsVotersSpacing), size: votersLayout.size) + animation.animator.updateFrame(layer: strongSelf.votersNode.layer, frame: votersFrame, completion: nil) + + if animation.isAnimated, let previousPoll = previousPoll, let poll = poll { + if previousPoll.results.totalVoters == nil && poll.results.totalVoters != nil { + strongSelf.votersNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + } + } + + if let statusSizeAndApply = statusSizeAndApply { + let statusFrame = CGRect(origin: CGPoint(x: resultSize.width - statusSizeAndApply.0.width - layoutConstants.text.bubbleInsets.right, y: votersFrame.maxY + statusOffset), size: statusSizeAndApply.0) + + if strongSelf.statusNode.supernode == nil { + statusSizeAndApply.1(.None) + strongSelf.statusNode.frame = statusFrame + strongSelf.addSubnode(strongSelf.statusNode) + } else { + statusSizeAndApply.1(animation) + animation.animator.updateFrame(layer: strongSelf.statusNode.layer, frame: statusFrame, completion: nil) + } + } else if strongSelf.statusNode.supernode != nil { + strongSelf.statusNode.removeFromSupernode() + } + + let _ = buttonSubmitInactiveTextApply() + strongSelf.buttonSubmitInactiveTextNode.frame = buttonSubmitInactiveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) + + let _ = buttonSubmitActiveTextApply() + strongSelf.buttonSubmitActiveTextNode.frame = buttonSubmitActiveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) + + let _ = buttonSaveTextApply() + strongSelf.buttonSaveTextNode.frame = buttonSaveTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) + + let _ = buttonViewResultsTextApply() + strongSelf.buttonViewResultsTextNode.frame = buttonViewResultsTextFrame.offsetBy(dx: 0.0, dy: verticalOffset) + + strongSelf.updateSelection() + strongSelf.updatePollTooltipMessageState(animated: false) + + let buttonWidth: CGFloat = floor(max(strongSelf.buttonSaveTextNode.frame.width, max(strongSelf.buttonViewResultsTextNode.frame.width, strongSelf.buttonSubmitActiveTextNode.frame.width)) * 1.1) + strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonWidth) / 2.0), y: verticalOffset), size: CGSize(width: buttonWidth, height: 44.0)) + + strongSelf.updateIsTranslating(isTranslating) + } + }) }) }) } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift index 92bd0fa3b8..f4df239aa5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift @@ -769,10 +769,10 @@ private final class ChatMessageTodoItemNode: ASDisplayNode { linkColor: messageTheme.linkTextColor, baseFont: presentationData.messageFont, linkFont: presentationData.messageFont, - boldFont: presentationData.messageFont, - italicFont: presentationData.messageFont, - boldItalicFont: presentationData.messageFont, - fixedFont: presentationData.messageFont, + boldFont: presentationData.messageBoldFont, + italicFont: presentationData.messageItalicFont, + boldItalicFont: presentationData.messageBoldItalicFont, + fixedFont: presentationData.messageFixedFont, blockQuoteFont: presentationData.messageFont, underlineLinks: underlineLinks, message: message diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/BUILD b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/BUILD index 6035b65862..d1c7e8b9d7 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/BUILD +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/BUILD @@ -24,6 +24,7 @@ swift_library( "//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer", "//submodules/TextFormat:TextFormat", "//submodules/AppBundle:AppBundle", + "//submodules/SearchBarNode:SearchBarNode", "//submodules/TelegramUI/Components/ChatInputNode:ChatInputNode", "//submodules/Components/PagerComponent:PagerComponent", "//submodules/PremiumUI:PremiumUI", diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchBarNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchBarNode.swift deleted file mode 100644 index e3e0272230..0000000000 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchBarNode.swift +++ /dev/null @@ -1,500 +0,0 @@ -import Foundation -import UIKit -import SwiftSignalKit -import AsyncDisplayKit -import Display -import TelegramPresentationData -import ActivityIndicator -import AppBundle -import FeaturedStickersScreen - -private func generateLoupeIcon(color: UIColor) -> UIImage? { - return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Loupe"), color: color) -} - -private func generateClearIcon(color: UIColor) -> UIImage? { - return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color) -} - -private func generateBackground(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? { - let diameter: CGFloat = 10.0 - return generateImage(CGSize(width: diameter, height: diameter), contextGenerator: { size, context in - context.setFillColor(backgroundColor.cgColor) - context.fill(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(foregroundColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - }, opaque: true)?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0)) -} - -private class PaneSearchBarTextField: UITextField { - public var didDeleteBackwardWhileEmpty: (() -> Void)? - - let placeholderLabel: ImmediateTextNode - var placeholderString: NSAttributedString? { - didSet { - self.placeholderLabel.attributedText = self.placeholderString - } - } - - let prefixLabel: ASTextNode - var prefixString: NSAttributedString? { - didSet { - self.prefixLabel.attributedText = self.prefixString - } - } - - override init(frame: CGRect) { - self.placeholderLabel = ImmediateTextNode() - self.placeholderLabel.isUserInteractionEnabled = false - self.placeholderLabel.displaysAsynchronously = false - self.placeholderLabel.maximumNumberOfLines = 1 - - self.prefixLabel = ASTextNode() - self.prefixLabel.isUserInteractionEnabled = false - self.prefixLabel.displaysAsynchronously = false - - super.init(frame: frame) - - self.addSubnode(self.placeholderLabel) - self.addSubnode(self.prefixLabel) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override var keyboardAppearance: UIKeyboardAppearance { - get { - return super.keyboardAppearance - } - set { - let resigning = self.isFirstResponder - if resigning { - self.resignFirstResponder() - } - super.keyboardAppearance = newValue - if resigning { - self.becomeFirstResponder() - } - } - } - - override func textRect(forBounds bounds: CGRect) -> CGRect { - if bounds.size.width.isZero { - return CGRect(origin: CGPoint(), size: CGSize()) - } - var rect = bounds.insetBy(dx: 4.0, dy: 4.0) - - let prefixSize = self.prefixLabel.measure(bounds.size) - if !prefixSize.width.isZero { - let prefixOffset = prefixSize.width - rect.origin.x += prefixOffset - rect.size.width -= prefixOffset - } - return rect - } - - override func editingRect(forBounds bounds: CGRect) -> CGRect { - return self.textRect(forBounds: bounds) - } - - override func layoutSubviews() { - super.layoutSubviews() - - let bounds = self.bounds - if bounds.size.width.isZero { - return - } - - let constrainedSize = self.textRect(forBounds: self.bounds).size - let labelSize = self.placeholderLabel.updateLayout(constrainedSize) - self.placeholderLabel.frame = CGRect(origin: CGPoint(x: self.textRect(forBounds: bounds).minX, y: self.textRect(forBounds: bounds).minY + 4.0), size: labelSize) - - let prefixSize = self.prefixLabel.measure(constrainedSize) - let prefixBounds = bounds.insetBy(dx: 4.0, dy: 4.0) - self.prefixLabel.frame = CGRect(origin: CGPoint(x: prefixBounds.minX, y: prefixBounds.minY + 1.0), size: prefixSize) - } - - override func deleteBackward() { - if self.text == nil || self.text!.isEmpty { - self.didDeleteBackwardWhileEmpty?() - } - super.deleteBackward() - } -} - -class PaneSearchBarNode: ASDisplayNode, UITextFieldDelegate { - var cancel: (() -> Void)? - var textUpdated: ((String, String) -> Void)? - var clearPrefix: (() -> Void)? - - private let backgroundNode: ASDisplayNode - private let separatorNode: ASDisplayNode - private let textBackgroundNode: ASImageNode - private var activityIndicator: ActivityIndicator? - private let iconNode: ASImageNode - private let textField: PaneSearchBarTextField - private let clearButton: HighlightableButtonNode - private let cancelButton: HighlightableButtonNode - - var placeholderString: NSAttributedString? { - get { - return self.textField.placeholderString - } set(value) { - self.textField.placeholderString = value - } - } - - var prefixString: NSAttributedString? { - get { - return self.textField.prefixString - } set(value) { - let previous = self.prefixString - let updated: Bool - if let previous = previous, let value = value { - updated = !previous.isEqual(to: value) - } else { - updated = (previous != nil) != (value != nil) - } - if updated { - self.textField.prefixString = value - self.textField.setNeedsLayout() - self.updateIsEmpty() - } - } - } - - var text: String { - get { - return self.textField.text ?? "" - } set(value) { - if self.textField.text ?? "" != value { - self.textField.text = value - self.textFieldDidChange(self.textField) - } - } - } - - var activity: Bool = false { - didSet { - if self.activity != oldValue { - if self.activity { - if self.activityIndicator == nil, let theme = self.theme { - let activityIndicator = ActivityIndicator(type: .custom(theme.chat.inputMediaPanel.stickersSearchControlColor, 13.0, 1.0, false)) - self.activityIndicator = activityIndicator - self.addSubnode(activityIndicator) - if let (boundingSize, leftInset, rightInset) = self.validLayout { - self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate) - } - } - } else if let activityIndicator = self.activityIndicator { - self.activityIndicator = nil - activityIndicator.removeFromSupernode() - } - self.iconNode.isHidden = self.activity - } - } - } - - private var validLayout: (CGSize, CGFloat, CGFloat)? - private var theme: PresentationTheme? - - override init() { - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - - self.textBackgroundNode = ASImageNode() - self.textBackgroundNode.isLayerBacked = false - self.textBackgroundNode.displaysAsynchronously = false - self.textBackgroundNode.displayWithoutProcessing = true - - self.iconNode = ASImageNode() - self.iconNode.isUserInteractionEnabled = false - self.iconNode.displaysAsynchronously = false - self.iconNode.displayWithoutProcessing = true - - self.textField = PaneSearchBarTextField() - self.textField.accessibilityTraits = .searchField - self.textField.autocorrectionType = .no - self.textField.returnKeyType = .search - self.textField.font = Font.regular(17.0) - - self.clearButton = HighlightableButtonNode() - self.clearButton.imageNode.displaysAsynchronously = false - self.clearButton.imageNode.displayWithoutProcessing = true - self.clearButton.displaysAsynchronously = false - self.clearButton.isHidden = true - - self.cancelButton = HighlightableButtonNode() - self.cancelButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0) - self.cancelButton.displaysAsynchronously = false - - super.init() - - self.addSubnode(self.backgroundNode) - self.addSubnode(self.separatorNode) - - self.addSubnode(self.textBackgroundNode) - self.view.addSubview(self.textField) - self.addSubnode(self.iconNode) - self.addSubnode(self.clearButton) - self.addSubnode(self.cancelButton) - - self.textField.delegate = self - self.textField.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: .editingChanged) - - self.textField.didDeleteBackwardWhileEmpty = { [weak self] in - self?.clearPressed() - } - - self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) - self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside) - } - - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { - self.theme = theme - - if let activityIndicator = self.activityIndicator { - activityIndicator.type = .custom(theme.chat.inputMediaPanel.stickersSearchControlColor, 13.0, 1.0, false) - } - self.separatorNode.backgroundColor = theme.chat.inputMediaPanel.panelSeparatorColor - self.textBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 36.0, color: theme.chat.inputMediaPanel.stickersSearchBackgroundColor) - self.textField.textColor = theme.chat.inputMediaPanel.stickersSearchPrimaryColor - self.iconNode.image = generateLoupeIcon(color: theme.chat.inputMediaPanel.stickersSearchControlColor) - self.clearButton.setImage(generateClearIcon(color: theme.chat.inputMediaPanel.stickersSearchControlColor), for: []) - self.cancelButton.setAttributedTitle(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.chat.inputPanel.panelControlAccentColor), for: []) - self.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance - self.textField.tintColor = theme.list.itemAccentColor - - if let (boundingSize, leftInset, rightInset) = self.validLayout { - self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate) - } - } - - func updateLayout(boundingSize: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) { - self.validLayout = (boundingSize, leftInset, rightInset) - - self.backgroundNode.frame = self.bounds - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: self.bounds.size.height), size: CGSize(width: self.bounds.size.width, height: UIScreenPixel))) - - let verticalOffset: CGFloat = -20.0 - - let contentFrame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: boundingSize.width - leftInset - rightInset, height: boundingSize.height)) - - let cancelButtonSize = self.cancelButton.measure(CGSize(width: 100.0, height: CGFloat.infinity)) - transition.updateFrame(node: self.cancelButton, frame: CGRect(origin: CGPoint(x: contentFrame.maxX - 8.0 - cancelButtonSize.width, y: verticalOffset + 36.0), size: cancelButtonSize)) - - let textBackgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX + 8.0, y: verticalOffset + 28.0), size: CGSize(width: contentFrame.width - 16.0 - cancelButtonSize.width - 11.0, height: 36.0)) - transition.updateFrame(node: self.textBackgroundNode, frame: textBackgroundFrame) - - let textFrame = CGRect(origin: CGPoint(x: textBackgroundFrame.minX + 27.0, y: textBackgroundFrame.minY), size: CGSize(width: max(1.0, textBackgroundFrame.size.width - 27.0 - 20.0), height: textBackgroundFrame.size.height)) - - if let iconImage = self.iconNode.image { - let iconSize = iconImage.size - transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.minX + 5.0, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - iconSize.height) / 2.0)), size: iconSize)) - } - - if let activityIndicator = self.activityIndicator { - let indicatorSize = activityIndicator.measure(CGSize(width: 32.0, height: 32.0)) - transition.updateFrame(node: activityIndicator, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.minX + 11.0, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - indicatorSize.height) / 2.0)), size: indicatorSize)) - } - - let clearSize = self.clearButton.measure(CGSize(width: 100.0, height: 100.0)) - transition.updateFrame(node: self.clearButton, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.maxX - 8.0 - clearSize.width, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - clearSize.height) / 2.0)), size: clearSize)) - - self.textField.frame = textFrame - self.textField.layoutSubviews() - } - - @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { - if let cancel = self.cancel { - cancel() - } - } - } - - func activate() { - self.textField.becomeFirstResponder() - } - - func animateIn(from node: PaneSearchBarPlaceholderNode, duration: Double, timingFunction: String, completion: @escaping () -> Void) { - let initialTextBackgroundFrame = node.view.convert(node.backgroundNode.frame, to: self.view) - - var backgroundCompleted = false - var separatorCompleted = false - var textBackgroundCompleted = false - let intermediateCompletion: () -> Void = { - if backgroundCompleted && separatorCompleted && textBackgroundCompleted { - completion() - } - } - - let initialBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.bounds.size.width, height: max(0.0, initialTextBackgroundFrame.maxY + 8.0))) - if let fromBackgroundColor = node.backgroundColor, let toBackgroundColor = self.backgroundNode.backgroundColor { - self.backgroundNode.layer.animate(from: fromBackgroundColor.cgColor, to: toBackgroundColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration * 0.7) - } else { - self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) - } - self.backgroundNode.layer.animateFrame(from: initialBackgroundFrame, to: self.backgroundNode.frame, duration: duration, timingFunction: timingFunction, completion: { _ in - backgroundCompleted = true - intermediateCompletion() - }) - - let initialSeparatorFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, initialTextBackgroundFrame.maxY + 8.0)), size: CGSize(width: self.bounds.size.width, height: UIScreenPixel)) - self.separatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) - self.separatorNode.layer.animateFrame(from: initialSeparatorFrame, to: self.separatorNode.frame, duration: duration, timingFunction: timingFunction, completion: { _ in - separatorCompleted = true - intermediateCompletion() - }) - - self.textBackgroundNode.layer.animateFrame(from: initialTextBackgroundFrame, to: self.textBackgroundNode.frame, duration: duration, timingFunction: timingFunction, completion: { _ in - textBackgroundCompleted = true - intermediateCompletion() - }) - - let labelFrame = self.textField.placeholderLabel.frame - let initialLabelNodeFrame = CGRect(origin: node.labelNode.view.convert(node.labelNode.bounds, to: self.textField.superview).origin, size: labelFrame.size) - self.textField.layer.animateFrame(from: CGRect(origin: initialLabelNodeFrame.origin.offsetBy(dx: -labelFrame.minX, dy: -labelFrame.minY), size: self.textField.frame.size), to: self.textField.frame, duration: duration, timingFunction: timingFunction) - - let iconFrame = self.iconNode.frame - let initialIconFrame = CGRect(origin: node.iconNode.view.convert(node.iconNode.bounds, to: self.iconNode.view.superview).origin, size: iconFrame.size) - self.iconNode.layer.animateFrame(from: initialIconFrame, to: self.iconNode.frame, duration: duration, timingFunction: timingFunction) - - let cancelButtonFrame = self.cancelButton.frame - self.cancelButton.layer.animatePosition(from: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: initialTextBackgroundFrame.minY + 2.0 + cancelButtonFrame.size.height / 2.0), to: self.cancelButton.layer.position, duration: duration, timingFunction: timingFunction) - node.isHidden = true - } - - func deactivate(clear: Bool = true) { - self.textField.resignFirstResponder() - if clear { - self.textField.text = nil - self.textField.placeholderLabel.isHidden = false - } - } - - func transitionOut(to node: PaneSearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { - let targetTextBackgroundFrame = node.view.convert(node.backgroundNode.view.frame, to: self.view) - - let duration: Double = 0.5 - let timingFunction = kCAMediaTimingFunctionSpring - - node.isHidden = true - self.clearButton.isHidden = true - self.textField.text = "" - - var backgroundCompleted = false - var separatorCompleted = false - var textBackgroundCompleted = false - let intermediateCompletion: () -> Void = { [weak node] in - if backgroundCompleted && separatorCompleted && textBackgroundCompleted { - completion() - node?.isHidden = false - } - } - - let targetBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.bounds.size.width, height: max(0.0, targetTextBackgroundFrame.maxY + 8.0))) - if let toBackgroundColor = node.backgroundColor, let fromBackgroundColor = self.backgroundNode.backgroundColor { - self.backgroundNode.layer.animate(from: fromBackgroundColor.cgColor, to: toBackgroundColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration * 0.5, removeOnCompletion: false) - } else { - self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration / 2.0, removeOnCompletion: false) - } - self.backgroundNode.layer.animateFrame(from: self.backgroundNode.frame, to: targetBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false, completion: { _ in - backgroundCompleted = true - intermediateCompletion() - }) - - let targetSeparatorFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, targetTextBackgroundFrame.maxY + 8.0)), size: CGSize(width: self.bounds.size.width, height: UIScreenPixel)) - self.separatorNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration / 2.0, removeOnCompletion: false) - self.separatorNode.layer.animateFrame(from: self.separatorNode.frame, to: targetSeparatorFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false, completion: { _ in - separatorCompleted = true - intermediateCompletion() - }) - - self.textBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false, completion: { _ in - textBackgroundCompleted = true - intermediateCompletion() - }) - - let transitionBackgroundNode = ASImageNode() - transitionBackgroundNode.isLayerBacked = true - transitionBackgroundNode.displaysAsynchronously = false - transitionBackgroundNode.displayWithoutProcessing = true - transitionBackgroundNode.image = node.backgroundNode.image - self.insertSubnode(transitionBackgroundNode, aboveSubnode: self.textBackgroundNode) - transitionBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration / 2.0, removeOnCompletion: false) - transitionBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - - let textFieldFrame = self.textField.frame - let targetLabelNodeFrame = CGRect(origin: node.labelNode.view.convert(node.labelNode.bounds, to: self.textField.superview).origin, size: textFieldFrame.size) - self.textField.layer.animateFrame(from: self.textField.frame, to: CGRect(origin: targetLabelNodeFrame.origin.offsetBy(dx: -self.textField.placeholderLabel.frame.minX, dy: -self.textField.placeholderLabel.frame.minY), size: self.textField.frame.size), duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - if let snapshot = node.labelNode.layer.snapshotContentTree() { - snapshot.frame = CGRect(origin: self.textField.placeholderLabel.frame.origin, size: node.labelNode.frame.size) - self.textField.layer.addSublayer(snapshot) - snapshot.animateAlpha(from: 0.0, to: 1.0, duration: duration * 2.0 / 3.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue) - //self.textField.placeholderLabel.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 3.0 / 2.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false) - - } - - let iconFrame = self.iconNode.frame - let targetIconFrame = CGRect(origin: node.iconNode.view.convert(node.iconNode.bounds, to: self.iconNode.view.superview).origin, size: iconFrame.size) - self.iconNode.image = node.iconNode.image - self.iconNode.layer.animateFrame(from: self.iconNode.frame, to: targetIconFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - - let cancelButtonFrame = self.cancelButton.frame - self.cancelButton.layer.animatePosition(from: self.cancelButton.layer.position, to: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: targetTextBackgroundFrame.minY + 4.0 + cancelButtonFrame.size.height / 2.0), duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - } - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - if string.range(of: "\n") != nil { - return false - } - return true - } - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - self.textField.resignFirstResponder() - return false - } - - @objc func textFieldDidChange(_ textField: UITextField) { - self.updateIsEmpty() - if let textUpdated = self.textUpdated { - textUpdated(textField.text ?? "", self.textField.textInputMode?.primaryLanguage ?? "") - } - } - - private func updateIsEmpty() { - let isEmpty = !(textField.text?.isEmpty ?? true) - if isEmpty != self.textField.placeholderLabel.isHidden { - self.textField.placeholderLabel.isHidden = isEmpty - } - self.clearButton.isHidden = !isEmpty && self.prefixString == nil - } - - @objc func cancelPressed() { - if let cancel = self.cancel { - cancel() - } - } - - @objc func clearPressed() { - if (self.textField.text?.isEmpty ?? true) { - if self.prefixString != nil { - self.clearPrefix?() - } - } else { - self.textField.text = "" - self.textFieldDidChange(self.textField) - } - } - - func updateQuery(_ query: String) { - self.textField.text = query - self.textFieldDidChange(self.textField) - } -} diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchContainerNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchContainerNode.swift index 759f4b04cf..31d8c7e2a5 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchContainerNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/PaneSearchContainerNode.swift @@ -2,6 +2,7 @@ import Foundation import UIKit import AsyncDisplayKit import Display +import SearchBarNode import SwiftSignalKit import Postbox import TelegramCore @@ -16,7 +17,23 @@ import StickerPeekUI import EntityKeyboardGifContent import BatchVideoRendering -private let searchBarHeight: CGFloat = 52.0 +private let searchBarHeight: CGFloat = 76.0 +private let searchBarTopInset: CGFloat = 16.0 +private let searchBarFieldHeight: CGFloat = 44.0 + +private func paneSearchBarTheme(_ theme: PresentationTheme) -> SearchBarNodeTheme { + return SearchBarNodeTheme( + background: .clear, + separator: .clear, + inputFill: .clear, + primaryText: theme.chat.inputPanel.panelControlColor, + placeholder: theme.chat.inputPanel.inputPlaceholderColor, + inputIcon: theme.chat.inputPanel.inputControlColor, + inputClear: theme.chat.inputPanel.panelControlColor, + accent: theme.chat.inputPanel.panelControlAccentColor, + keyboard: theme.rootController.keyboardColor + ) +} public protocol PaneSearchContentNode { var ready: Signal { get } @@ -43,9 +60,10 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer private let peekBehavior: EmojiContentPeekBehavior? private let backgroundNode: ASDisplayNode - private let searchBar: PaneSearchBarNode + private let searchBar: SearchBarNode private var validLayout: CGSize? + private weak var animatedPlaceholder: PaneSearchBarPlaceholderNode? public var onCancel: (() -> Void)? @@ -69,7 +87,13 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer } self.backgroundNode = ASDisplayNode() - self.searchBar = PaneSearchBarNode() + self.searchBar = SearchBarNode( + theme: paneSearchBarTheme(theme), + presentationTheme: theme, + strings: strings, + fieldStyle: .glass, + displayBackground: false + ) super.init() @@ -87,9 +111,8 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer } self.searchBar.cancel = { [weak self] in + self?.searchBar.deactivate(clear: false) cancel() - - self?.searchBar.view.endEditing(true) self?.onCancel?() } self.searchBar.activate() @@ -150,7 +173,7 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { self.backgroundNode.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0) self.contentNode.updateThemeAndStrings(theme: theme, strings: strings) - self.searchBar.updateThemeAndStrings(theme: theme, strings: strings) + self.searchBar.updateThemeAndStrings(theme: paneSearchBarTheme(theme), presentationTheme: theme, strings: strings) let placeholder: String switch mode { @@ -159,11 +182,11 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer case .sticker, .trending: placeholder = strings.Stickers_Search } - self.searchBar.placeholderString = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: theme.chat.inputMediaPanel.stickersSearchPlaceholderColor) + self.searchBar.placeholderString = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor) } public func updateQuery(_ query: String) { - self.searchBar.updateQuery(query) + self.searchBar.text = query } public func itemAt(point: CGPoint) -> (ASDisplayNode, Any)? { @@ -174,8 +197,9 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer self.validLayout = size transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrame(node: self.searchBar, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: searchBarHeight))) - self.searchBar.updateLayout(boundingSize: CGSize(width: size.width, height: searchBarHeight), leftInset: leftInset, rightInset: rightInset, transition: transition) + let searchBarFrame = CGRect(origin: CGPoint(x: 0.0, y: searchBarTopInset), size: CGSize(width: size.width, height: searchBarFieldHeight)) + transition.updateFrame(node: self.searchBar, frame: searchBarFrame) + self.searchBar.updateLayout(boundingSize: searchBarFrame.size, leftInset: leftInset, rightInset: rightInset, transition: transition) let contentFrame = CGRect(origin: CGPoint(x: leftInset, y: searchBarHeight), size: CGSize(width: size.width - leftInset - rightInset, height: size.height - searchBarHeight)) @@ -190,6 +214,9 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer public func animateIn(from placeholder: PaneSearchBarPlaceholderNode?, anchorTop: CGPoint, anhorTopView: UIView, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { var verticalOrigin: CGFloat = anhorTopView.convert(anchorTop, to: self.view).y if let placeholder = placeholder { + self.animatedPlaceholder = placeholder + placeholder.isHidden = true + let placeholderFrame = placeholder.view.convert(placeholder.bounds, to: self.view) verticalOrigin = placeholderFrame.minY - 4.0 self.contentNode.animateIn(additivePosition: verticalOrigin, transition: transition) @@ -197,33 +224,65 @@ public final class PaneSearchContainerNode: ASDisplayNode, EntitySearchContainer self.contentNode.animateIn(additivePosition: 0.0, transition: transition) } + let searchBarFrame = self.searchBar.frame + let initialSearchBarFrame = CGRect(origin: CGPoint(x: searchBarFrame.minX, y: verticalOrigin), size: searchBarFrame.size) + switch transition { case let .animated(duration, curve): self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration / 2.0) - if let placeholder = placeholder { - self.searchBar.animateIn(from: placeholder, duration: duration, timingFunction: curve.timingFunction, completion: completion) - } else { - self.searchBar.alpha = 0.0 - transition.updateAlpha(node: self.searchBar, alpha: 1.0) - } + + self.searchBar.alpha = 1.0 + self.searchBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration, timingFunction: curve.timingFunction, completion: { _ in + completion() + }) + self.searchBar.layer.animateFrame(from: initialSearchBarFrame, to: searchBarFrame, duration: duration, timingFunction: curve.timingFunction) + if let size = self.validLayout { let initialBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin), size: CGSize(width: size.width, height: max(0.0, size.height - verticalOrigin))) self.backgroundNode.layer.animateFrame(from: initialBackgroundFrame, to: self.backgroundNode.frame, duration: duration, timingFunction: curve.timingFunction) } case .immediate: + completion() break } } public func animateOut(to placeholder: PaneSearchBarPlaceholderNode, animateOutSearchBar: Bool, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { + let finish: () -> Void = { [weak self] in + placeholder.isHidden = false + if let self, self.animatedPlaceholder === placeholder { + self.animatedPlaceholder = nil + } + completion() + } + if case let .animated(duration, curve) = transition { + let placeholderFrame = placeholder.view.convert(placeholder.bounds, to: self.view) + let verticalOrigin = placeholderFrame.minY - 4.0 + let targetSearchBarFrame = CGRect(origin: CGPoint(x: self.searchBar.frame.minX, y: verticalOrigin), size: self.searchBar.frame.size) + if let size = self.validLayout { - let placeholderFrame = placeholder.view.convert(placeholder.bounds, to: self.view) - let verticalOrigin = placeholderFrame.minY - 4.0 self.backgroundNode.layer.animateFrame(from: self.backgroundNode.frame, to: CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin), size: CGSize(width: size.width, height: max(0.0, size.height - verticalOrigin))), duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false) } + + self.searchBar.layer.animateFrame(from: self.searchBar.frame, to: targetSearchBarFrame, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false) + if animateOutSearchBar { + self.searchBar.alpha = 0.0 + self.searchBar.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { _ in + finish() + }) + } else { + self.searchBar.layer.animateAlpha(from: self.searchBar.alpha, to: self.searchBar.alpha, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { _ in + finish() + }) + } + } else { + if animateOutSearchBar { + self.searchBar.alpha = 0.0 + } + finish() } - self.searchBar.transitionOut(to: placeholder, transition: transition, completion: completion) + transition.updateAlpha(node: self.backgroundNode, alpha: 0.0) if animateOutSearchBar { transition.updateAlpha(node: self.searchBar, alpha: 0.0) diff --git a/submodules/TelegramUI/Components/ChatScheduleTimeController/BUILD b/submodules/TelegramUI/Components/ChatScheduleTimeController/BUILD index 8fa859ea8f..90488ae6ce 100644 --- a/submodules/TelegramUI/Components/ChatScheduleTimeController/BUILD +++ b/submodules/TelegramUI/Components/ChatScheduleTimeController/BUILD @@ -25,6 +25,7 @@ swift_library( "//submodules/TelegramUI/Components/ToastComponent", "//submodules/Markdown", "//submodules/UndoUI", + "//submodules/TooltipUI", "//submodules/TelegramUI/Components/LottieComponent", "//submodules/Components/MultilineTextComponent", "//submodules/Components/BundleIconComponent", @@ -36,6 +37,7 @@ swift_library( "//submodules/TelegramUI/Components/GlassBackgroundComponent", "//submodules/TelegramUI/Components/GlassBarButtonComponent", "//submodules/TelegramUI/Components/PlainButtonComponent", + "//submodules/Components/LottieAnimationComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift index 782a1ff862..c1e232f39c 100644 --- a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift +++ b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift @@ -13,10 +13,12 @@ import SheetComponent import ButtonComponent import PlainButtonComponent import BundleIconComponent +import LottieAnimationComponent import GlassBackgroundComponent import GlassBarButtonComponent import DatePickerNode import UndoUI +import TooltipUI private let calendar = Calendar(identifier: .gregorian) @@ -66,6 +68,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component { final class View: UIView { private let cancel = ComponentView() + private let silent = ComponentView() + private let title = ComponentView() private let button = ComponentView() private let secondaryButton = ComponentView() @@ -93,13 +97,15 @@ private final class ChatScheduleTimeSheetContentComponent: Component { private var monthHeight: CGFloat? + private var isSilentPosting = false + private var date: Date? private var minDate: Date? private var maxDate: Date? private var isPickingTime = false private var isPickingRepeatPeriod = false - + private var repeatPeriod: Int32? private let dateFormatter: DateFormatter @@ -144,6 +150,65 @@ private final class ChatScheduleTimeSheetContentComponent: Component { } } + private func presentSilentPostingTooltip() { + guard let component = self.component, let sourceView = self.silent.view else { + return + } + + let peerId: EnginePeer.Id? + switch component.mode { + case let .scheduledMessages(peerIdValue, _): + peerId = peerIdValue + case .reminders: + peerId = component.context.account.peerId + default: + peerId = nil + } + guard let peerId else { + return + } + + let isSilentPosting = self.isSilentPosting + let _ = (component.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let self, let peer, let controller = self.environment?.controller() else { + return + } + + var isChannel = false + if case let .channel(channel) = peer, case .broadcast = channel.info { + isChannel = true + } + + //TODO:localize + let text: String + if case .user = peer { + if isSilentPosting { + text = "\(peer.compactDisplayTitle) will receive a silent notification" + } else { + text = "\(peer.compactDisplayTitle) will be notified" + } + } else if isChannel { + if isSilentPosting { + text = "Subscribers will receive a silent notification" + } else { + text = "Subscribers will be notified" + } + } else { + if isSilentPosting { + text = "Members will receive a silent notification" + } else { + text = "Members will be notified" + } + } + + let sourceFrame = sourceView.convert(sourceView.bounds, to: nil) + controller.present(TooltipScreen(account: component.context.account, sharedContext: component.context.sharedContext, text: .plain(text: text), style: .default, icon: .none, location: .point(sourceFrame, .bottom), shouldDismissOnTouch: { _, _ in + return .dismiss(consume: false) + }), in: .window(.root)) + }) + } + func update(component: ChatScheduleTimeSheetContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.isUpdating = true defer { @@ -184,40 +249,6 @@ private final class ChatScheduleTimeSheetContentComponent: Component { var contentHeight: CGFloat = 0.0 contentHeight += 30.0 - let barButtonSize = CGSize(width: 44.0, height: 44.0) - let cancelSize = self.cancel.update( - transition: transition, - component: AnyComponent( - GlassBarButtonComponent( - size: barButtonSize, - backgroundColor: nil, - isDark: environment.theme.overallDarkAppearance, - state: .glass, - component: AnyComponentWithIdentity(id: "close", component: AnyComponent( - BundleIconComponent( - name: "Navigation/Close", - tintColor: environment.theme.chat.inputPanel.panelControlColor - ) - )), - action: { [weak self] _ in - guard let self, let component = self.component else { - return - } - component.dismiss() - } - ) - ), - environment: {}, - containerSize: barButtonSize - ) - let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize) - if let cancelView = self.cancel.view { - if cancelView.superview == nil { - self.addSubview(cancelView) - } - transition.setFrame(view: cancelView, frame: cancelFrame) - } - let title: String switch component.mode { case .scheduledMessages: @@ -595,7 +626,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component { transition.setFrame(view: buttonView, frame: buttonFrame) } contentHeight += buttonSize.height - } else if case .scheduledMessages(true) = component.mode { + } else if case .scheduledMessages(_, true) = component.mode { contentHeight += 8.0 let buttonSize = self.secondaryButton.update( @@ -784,6 +815,87 @@ private final class ChatScheduleTimeSheetContentComponent: Component { component.externalState.repeatValueFrame = repeatValueFrame + let barButtonSize = CGSize(width: 44.0, height: 44.0) + let cancelSize = self.cancel.update( + transition: transition, + component: AnyComponent( + GlassBarButtonComponent( + size: barButtonSize, + backgroundColor: nil, + isDark: environment.theme.overallDarkAppearance, + state: .glass, + component: AnyComponentWithIdentity(id: "close", component: AnyComponent( + BundleIconComponent( + name: "Navigation/Close", + tintColor: environment.theme.chat.inputPanel.panelControlColor + ) + )), + action: { [weak self] _ in + guard let self, let component = self.component else { + return + } + component.dismiss() + } + ) + ), + environment: {}, + containerSize: barButtonSize + ) + let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize) + if let cancelView = self.cancel.view { + if cancelView.superview == nil { + self.addSubview(cancelView) + } + transition.setFrame(view: cancelView, frame: cancelFrame) + } + + switch component.mode { + case .scheduledMessages, .reminders: + let silentSize = self.silent.update( + transition: transition, + component: AnyComponent( + GlassBarButtonComponent( + size: barButtonSize, + backgroundColor: nil, + isDark: environment.theme.overallDarkAppearance, + state: .glass, + component: AnyComponentWithIdentity(id: "silent", component: AnyComponent( + LottieAnimationComponent( + animation: LottieAnimationComponent.AnimationItem( + name: self.isSilentPosting ? "NavigationMuteOn" : "NavigationMuteOff", + mode: !transition.animation.isImmediate ? .animating(loop: false) : .still(position: .end), + range: nil, + waitForCompletion: false + ), + colors: ["__allcolors__": environment.theme.chat.inputPanel.panelControlColor], + size: CGSize(width: 30.0, height: 30.0) + ) + )), + action: { [weak self] _ in + guard let self else { + return + } + self.isSilentPosting = !self.isSilentPosting + self.state?.updated(transition: .easeInOut(duration: 0.2)) + + self.presentSilentPostingTooltip() + } + ) + ), + environment: {}, + containerSize: barButtonSize + ) + let silentFrame = CGRect(origin: CGPoint(x: availableSize.width - 16.0 - silentSize.width, y: 16.0), size: silentSize) + if let silentView = self.silent.view { + if silentView.superview == nil { + self.addSubview(silentView) + } + transition.setFrame(view: silentView, frame: silentFrame) + } + default: + break + } + return contentSize } } @@ -958,7 +1070,7 @@ private final class ChatScheduleTimeScreenComponent: Component { public class ChatScheduleTimeScreen: ViewControllerComponentContainer { public enum Mode: Equatable { - case scheduledMessages(sendWhenOnlineAvailable: Bool) + case scheduledMessages(peerId: EnginePeer.Id, sendWhenOnlineAvailable: Bool) case reminders case format case poll diff --git a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift index 30234ff2b2..eafa125640 100644 --- a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift +++ b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift @@ -975,6 +975,12 @@ final class ComposeTodoScreenComponent: Component { } } }, + present: { [weak self] c in + guard let controller = self?.environment?.controller() else { + return + } + controller.present(c, in: .window(.root)) + }, tag: todoItem.textFieldTag )))) diff --git a/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextActionsContainerNode.swift b/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextActionsContainerNode.swift index 0ef201b886..09b4cb1251 100644 --- a/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextActionsContainerNode.swift +++ b/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextActionsContainerNode.swift @@ -424,6 +424,13 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode { self.text = self.presentationData.strings.Camera_CollageReorderingInfo self.targetSelectionIndex = nil icon = UIImage(bundleImageName: "Chat/Context Menu/Tip") + case .deleteReaction: + self.action = nil + //TODO:localize + self.text = "Tap and hold to delete reaction." + self.targetSelectionIndex = nil + icon = nil + isUserInteractionEnabled = false } self.iconNode = ASImageNode() diff --git a/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift b/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift index e048c1e86b..7736448cde 100644 --- a/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift +++ b/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift @@ -93,15 +93,23 @@ public final class ListActionItemComponent: Component { public enum LeftIcon: Equatable { public final class Check: Equatable { + public enum Style { + case round + case rectangle + } + + public let style: Style public let isSelected: Bool public let isEnabled: Bool public let toggle: (() -> Void)? public init( + style: Style = .round, isSelected: Bool, isEnabled: Bool = true, toggle: (() -> Void)? ) { + self.style = style self.isSelected = isSelected self.isEnabled = isEnabled self.toggle = toggle @@ -111,6 +119,9 @@ public final class ListActionItemComponent: Component { if lhs === rhs { return true } + if lhs.style != rhs.style { + return false + } if lhs.isSelected != rhs.isSelected { return false } @@ -318,12 +329,12 @@ public final class ListActionItemComponent: Component { self.action?() } - func update(size: CGSize, theme: PresentationTheme, isSelected: Bool, transition: ComponentTransition) { + func update(size: CGSize, theme: PresentationTheme, isSelected: Bool, isRectangle: Bool = false, transition: ComponentTransition) { let checkLayer: CheckLayer if let current = self.checkLayer { checkLayer = current } else { - checkLayer = CheckLayer(theme: CheckNodeTheme(theme: theme, style: .plain), content: .check(isRectangle: false)) + checkLayer = CheckLayer(theme: CheckNodeTheme(theme: theme, style: .plain), content: .check(isRectangle: isRectangle)) self.checkLayer = checkLayer self.layer.addSublayer(checkLayer) } @@ -625,11 +636,11 @@ public final class ListActionItemComponent: Component { leftCheckView.frame = CGRect(origin: CGPoint(x: -checkSize.width, y: self.bounds.height == 0.0 ? checkFrame.minY : floor((self.bounds.height - checkSize.height) * 0.5)), size: checkFrame.size) transition.setPosition(view: leftCheckView, position: checkFrame.center) transition.setBounds(view: leftCheckView, bounds: CGRect(origin: CGPoint(), size: checkFrame.size)) - leftCheckView.update(size: checkFrame.size, theme: component.theme, isSelected: check.isSelected, transition: .immediate) + leftCheckView.update(size: checkFrame.size, theme: component.theme, isSelected: check.isSelected, isRectangle: check.style == .rectangle, transition: .immediate) } else { transition.setPosition(view: leftCheckView, position: checkFrame.center) transition.setBounds(view: leftCheckView, bounds: CGRect(origin: CGPoint(), size: checkFrame.size)) - leftCheckView.update(size: checkFrame.size, theme: component.theme, isSelected: check.isSelected, transition: transition) + leftCheckView.update(size: checkFrame.size, theme: component.theme, isSelected: check.isSelected, isRectangle: check.style == .rectangle, transition: transition) } case let .custom(customLeftIcon, adjustLeftInset): var resetLeftIcon = false diff --git a/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift b/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift index 8ca1510769..ab3cced9f4 100644 --- a/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift +++ b/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift @@ -130,6 +130,7 @@ public final class ListComposePollOptionComponent: Component { public let canReorder: Bool public let canAdd: Bool public let attachment: Attachment? + public let formattingAvailable: Bool public let emptyLineHandling: TextFieldComponent.EmptyLineHandling public let returnKeyType: UIReturnKeyType public let returnKeyAction: (() -> Void)? @@ -141,6 +142,7 @@ public final class ListComposePollOptionComponent: Component { public let attachAction: (() -> Void)? public let deleteAction: (() -> Void)? public let paste: ((TextFieldComponent.PasteData) -> Void)? + public let present: ((ViewController) -> Void)? public let tag: AnyObject? public init( @@ -159,6 +161,7 @@ public final class ListComposePollOptionComponent: Component { canReorder: Bool = false, canAdd: Bool = false, attachment: Attachment? = nil, + formattingAvailable: Bool = false, emptyLineHandling: TextFieldComponent.EmptyLineHandling, returnKeyType: UIReturnKeyType = .next, returnKeyAction: (() -> Void)? = nil, @@ -170,6 +173,7 @@ public final class ListComposePollOptionComponent: Component { attachAction: (() -> Void)? = nil, deleteAction: (() -> Void)? = nil, paste: ((TextFieldComponent.PasteData) -> Void)? = nil, + present: ((ViewController) -> Void)? = nil, tag: AnyObject? = nil ) { self.externalState = externalState @@ -187,6 +191,7 @@ public final class ListComposePollOptionComponent: Component { self.canReorder = canReorder self.canAdd = canAdd self.attachment = attachment + self.formattingAvailable = formattingAvailable self.emptyLineHandling = emptyLineHandling self.returnKeyType = returnKeyType self.returnKeyAction = returnKeyAction @@ -198,6 +203,7 @@ public final class ListComposePollOptionComponent: Component { self.attachAction = attachAction self.deleteAction = deleteAction self.paste = paste + self.present = present self.tag = tag } @@ -247,6 +253,9 @@ public final class ListComposePollOptionComponent: Component { if lhs.attachment != rhs.attachment { return false } + if lhs.formattingAvailable != rhs.formattingAvailable { + return false + } if lhs.emptyLineHandling != rhs.emptyLineHandling { return false } @@ -732,11 +741,15 @@ public final class ListComposePollOptionComponent: Component { enableInlineAnimations: component.enableInlineAnimations, emptyLineHandling: component.emptyLineHandling, externalHandlingForMultilinePaste: true, - formatMenuAvailability: .none, + formatMenuAvailability: component.formattingAvailable ? .available([.bold, .italic, .strikethrough, .underline, .monospace, .spoiler, .link]) : .none, returnKeyType: component.returnKeyType, lockedFormatAction: { }, - present: { _ in + present: { [weak self] c in + guard let self, let component = self.component else { + return + } + component.present?(c) }, paste: { [weak self] data in guard let self, let component = self.component else { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift index d81eca2ccd..17a891e9f2 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift @@ -167,7 +167,11 @@ private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode { let height = textSize.height + verticalInset * 2.0 - transition.updateFrame(node: self.textNode, frame: textFrame) + if self.textNode.frame.size != textFrame.size { + self.textNode.frame = textFrame + } else { + transition.updateFrame(node: self.textNode, frame: textFrame) + } self.activateArea.frame = CGRect(origin: CGPoint(x: safeInsets.left, y: 0.0), size: CGSize(width: width - safeInsets.left - safeInsets.right, height: height)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift index 732d19be82..315eb8f421 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift @@ -375,17 +375,30 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte items[.help]!.append(PeerInfoScreenCommentItem(id: ItemNameHelp, text: presentationData.strings.EditProfile_NameAndPhotoOrVideoHelp)) if let cachedData = data.cachedData as? CachedUserData { - items[.bio]!.append(PeerInfoScreenMultilineInputItem(id: ItemBio, text: state.updatingBio ?? (cachedData.about ?? ""), placeholder: presentationData.strings.UserInfo_About_Placeholder, textUpdated: { updatedText in + let currentBio = state.updatingBio ?? (cachedData.about ?? "") + items[.bio]!.append(PeerInfoScreenMultilineInputItem(id: ItemBio, text: currentBio, placeholder: presentationData.strings.UserInfo_About_Placeholder, textUpdated: { updatedText in interaction.updateBio(updatedText) }, action: { interaction.dismissInput() }, maxLength: Int(data.globalSettings?.userLimits.maxAboutLength ?? 70))) - items[.bio]!.append(PeerInfoScreenCommentItem(id: ItemBioHelp, text: presentationData.strings.Settings_About_PrivacyHelp, linkAction: { _ in + + + var bioPrivacyInfo = presentationData.strings.Settings_About_PrivacyHelpEmpty + if let bioPrivacy = data.globalSettings?.privacySettings?.bio, !currentBio.isEmpty { + switch bioPrivacy { + case .enableEveryone: + bioPrivacyInfo = presentationData.strings.Settings_About_PrivacyHelpEveryone + case .enableContacts: + bioPrivacyInfo = presentationData.strings.Settings_About_PrivacyHelpContacts + case .disableEveryone: + bioPrivacyInfo = presentationData.strings.Settings_About_PrivacyHelpNobody + } + } + items[.bio]!.append(PeerInfoScreenCommentItem(id: ItemBioHelp, text: bioPrivacyInfo, linkAction: { _ in interaction.openBioPrivacy() })) } - var birthday: TelegramBirthday? if let updatingBirthDate = state.updatingBirthDate { birthday = updatingBirthDate @@ -414,14 +427,22 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte })) } - - var birthdayIsForContactsOnly = false - if let birthdayPrivacy = data.globalSettings?.privacySettings?.birthday, case .enableContacts = birthdayPrivacy { - birthdayIsForContactsOnly = true + var birthdayPrivacyInfo = "" + if let birthdayPrivacy = data.globalSettings?.privacySettings?.birthday { + switch birthdayPrivacy { + case .enableEveryone: + birthdayPrivacyInfo = presentationData.strings.Settings_Birthday_PrivacyHelpEveryone + case .enableContacts: + birthdayPrivacyInfo = presentationData.strings.Settings_Birthday_PrivacyHelpContacts + case .disableEveryone: + birthdayPrivacyInfo = presentationData.strings.Settings_Birthday_PrivacyHelpNobody + } + } + if !birthdayPrivacyInfo.isEmpty { + items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: birthdayPrivacyInfo, linkAction: { _ in + interaction.openBirthdatePrivacy() + })) } - items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: birthdayIsForContactsOnly ? presentationData.strings.Settings_Birthday_ContactsHelp : presentationData.strings.Settings_Birthday_Help, linkAction: { _ in - interaction.openBirthdatePrivacy() - })) if let user = data.peer as? TelegramUser { items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, icon: PresentationResourcesSettings.recentCalls, action: { diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/Contents.json new file mode 100644 index 0000000000..da60b22b56 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "incoming_call_20.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/incoming_call_20.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/CallIncomingIcon.imageset/incoming_call_20.pdf new file mode 100644 index 0000000000000000000000000000000000000000..af90dd7613ec14b9f87ae5e96f3c421d161de264 GIT binary patch literal 6022 zcma)Ac|25I+$T$=y(E&lXtR#N41+|L$TlPqV$56&vzaB6C5pC(N@Q1(7NkVTUZD^P zrR-6jBv1B`EbqNDh^OcMyzl*E=APgAo$qfy_nhA@tiGWFQc+E4S0MBVAps?T>f#{; z09slA!W5*qG2H=Wh-d|opa*f7<-$Bk0|A7snduzKnlm;7nK%NDiGzsR+CmH_9mJ7^ zwDz-UIJ_sw1YAHjB4wYH6hI{GlRAnrQ!=CJf$l^jA3Av0$J`q4XtYntoynwWAQ0Z(-iqET zid4EA0*S$35K77jWn~43LxFLU!o;x^C=6*1#vF=1$iUNyG$xTs0bo>|3zfx$ROOmC zCxC!oz^Ae3Bn~HBA!Y{uyHhqU5RT4>{KlR zUV}+wl0eun?!z%pm&E){nNyZTgcZ^t;V5qVq}U1s&=tobF{QNk5-AWik>cinR8hm@ zNF?}QSxH6<0h>f3{s!Vw7GY~4{w*I?2$sOYx&2$G130(ePzyR~?*%FUtEfdwIHHy! zbJbZC11>zr0gI?}VW1IQSvWX_7R4GzB$7Gt;7lSY3%`sNQ3j6nJ^< zN=wd}Me$^vQ@D91kaTNfI1g^+`i;*VH&~wDV4%aKpNS^%NuV1Y9hRZ5+hF2 z(4~`^#zdE3Inb-#Z-yuq^0SRUxNyU6w?h*~5|-#_2|E`%ZJ7g6WoDbI)WvYiDa)2u zNj3r`?T@nwE5s^!$m!|i*|Hn6o>jGk8>3g20g0=0Mid_EU&HLstEPzR=$nTMz6%to z<9iv%OA6$p3HCn|p9s=fFC_Kc7%xPf7a!Ww=wjfbYFiecVhm<^8DSm93fZkQ?YT%-5xA}CE5%Erls1h8@^xa_ zo42jISJv0*z*ch*JX&_I({)11k8gY6ok0`!RsrnJYeI*XztBNi%3A}nLYvQTOhP9O zTi!|Wu;xo!(->3`6n<;B<&Jt=)y-xHRqATp_m2vxZn=KBBUn*CI@#i8e0}>@&956q zg(v0CovD8ogG*2%ney-69&xs+?3#-Q(k!MrhPOuai-btXk>^`+5|2(b8Ihz;?8{y6 zyQ1~N_wq5^!OXYn+sxOvont%~_@u6mR9xr1-do6<_rn$OGXG~0gDq_FqIKFri1MCJ zlc7CB5)-GU7*nftPdn?-r1&?ogL8tV4y;MKL<>MGOt^6kHO@)B32hBD)rk*WtKjclai!|l4=vx1A_{Sw-YODs<5C1F>~^k3Wi zS4>vC)xmuIlcqm`gOQKJ@YO@z=;|YtsOlfp#o>D@#VdU)GoqaKILQXs%tTGyUZ(pT zd-~2Z%ck4dB$_$S2zTsin)?IMl$cw#DQv5uxKDW-&8x6g_80G6yU#T34R6@H*`P5w zE5+d(+GEWRWmf39J7V=s+4{$LzwbGQARn?bZnnXgV(jw|{4C0{7P#Y*QfgytBV&b0 zR!$ivp8m4zioldWp@^#dSEs?_tfaI;StpcJjwMUyN5odg*Y*m=Ez+#)g49X+ z5BVQu-=Z7$Y-teDKy)kCII&&3_}18#SxejEi(euy#czEZcPy?Xju^Kbg&>-Hq`K#O z?(&FqXStiXAI@>i5op=fvL)N8F0yy~D8WapI9~fsa?>m82Y!LE7&cwfZZ*_6hz9^>$|D=aM@JK)RAToXW0VBON zeKrf3)74_#)aIyf*ZtUibx&_ zr7%TZ8e(*74tzOsFf{qzXV;1o6<5s1%w6uOmQ7`^V~kTpUjwj~&h#aU5vvJwLQ+u(eOE{5^ru%=$+rVEOE&nRedp zz_7sKzXXs-lrG<*sDbdIMb@YNbL4}~{S5Qt{--WYZLN)ajEspHjEO)dVooP` z)H3BYbCpm0RsCsuXGwSd$RYM7zb&VbvnLZw9K71tMJ7`v6BqfP1UCd5^O|54+1I~D zvv&^pTRArj-EQt4?0zZicgXY=CMjIWxaoRYWZd{*Yc#}j zDWc6^Gc!FlWy_p6{K2*Ob$)zB?gRys8JUM7_E9l5m=_r8le1LM>c*P(aLs~tZ(si# z4mb8v-OrC)me#D-6wvhbR%l_-K78;yKJ#PQ{WA?`-kfbK?b~lViybTbr$4W~*kH`y z{J8V@it*L`tXAJ!wwY|lp|2%(e#M!5-Su-9bv&av;K94x(MsM=yj8r!=J2fdL6ghJ zw@o?Rz-nW=?CNb(E%WaWPfKLAyvFyjRFCJyz8t_f{*oqsC z!HuI+l~b7yZHjYmj#YbgdG%iG+|%{93TRtN$pLo!_wM5vfmoh%w-%-sQopF39 zpPpKg+*5ia`u_J12@kIq))sZp%VrEm%nIYpo;FXvf9LtJ)vvnCrjK0FO7;)=r7_t) ziRc(AVEnE4tN+qzkk3CzPHPi=p?`~$XB z$5s{X7oJV=1E;=4?{A+i!fZyO#*U5pjAfLnc~CDu&GBzVNvKXwIKC>39sjxGop!=R z8q3FXrG8#T2hNPeE9%brEwYHp5AYi>qV%45rTn1^NrF0H7S{*S{h zYT@{)3?CooPo?MuvORz>*3&zHV}JwzKC4;*jtg9B3taG-SdU7g(hoy-Mv!v>)k6X> ziWPL&U3}hEU$W-^Jk(-fh^1#)UUH-vWvANev*WD43Umlo!ZKd5qIRwuy7_hag7_aT zH*)R2;%6P*x`yC^@5-4N??|2+PV4F0QL!q3^6_$X;_URyc=Uei$2U%=eD}>@va4py zf2vQ7s_#4X_=+ACQ?41?ait<>c1KBj$@b!W_k!yhaqP>nJ(|wnDv^qH^svH=n*Mvo z>}3=;Rr;T+J>$^+y0#VBGAtV8+j7ol%&SDAW3sY#K$fg%Jif{3h(aw%4C9lK{5lMy zaly=_kC6PnE_TGhOmAlb;r(uqNI}JxNVyZndZT(s`RO71r9JJsTk@Zk3Xpb759HA_ zmalBF7tAWZ>mivHD(NZJyS?E#Gv&@(;xmg%vDcx$P_JXQny61yroPZu8dXYkNX%@w zFBbc16i74q>Wm)n54P#rcGSo%97jvY-XteD0{8-lWcECyb)!a=YLZ^R478Sd zTT>OFIaq4@Hdjy*ojVgKS8y|VgG=#eevMA?`!#Vbd$iB>PV*W(-8Q(|Mbzw=t{P5J z>;1OKf#y)l%m|ljipTV2iH~-991>U7*q#i^^J(gc7PcJ^%13mc)OmtOU9qz!$%oZQ z*6jWs{=AeX<(M8G!DlL?eVedqVAad~8%El4r;XgGHmmx4GK!w271^F4*II;4nO-iw zQ)7x zT4uX>#ms57j=`Gf&wWF`hU8|WXZUnyEL#3!1Aq&Rd)rl4R$r)Wq|yQzE^QMc0lw}c z;T99T0dVh~dQ=vL2_WZ2^VeKAkio6j`Mrd*iYo%f(xp(SObBfrg?ljuI1=YORaPK_ z%A(^z1^{m{^HejCK*SxOvf+!jq7vu%{i3`;`u#R9;2ZSlV#lS`D`)%t1EO1U$JA z&)+k^V&ga(aR>_4$V(tYcms-3uET&Kk4uCsrbGl=pb{u1Al5^dr2lZV^R5yri zk-ylGjY3KQ5-r3{bNClPqfja+z;(?64GDRbGecRRsiXdbrUn(!zxXidKloJ8C@9gE z@~NQJ{^V1GbM#+)YJcLXqW_euipD_u&C<21YJbX5#i&DPhoyWdCAB|kNVPw7K`CRP z&1-%wla3>jK)Mi|DaQIxHSJYZR(DWRQ&vTxm1O=k;_Md)IDG-wx7>n8947jJa44Yo VFqlwXbAp3HVN`{7?J}@1{2wCMV!8kT literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/Contents.json new file mode 100644 index 0000000000..9b101ab4da --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "outgoing_call_20.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/outgoing_call_20.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/CallOutgoingIcon.imageset/outgoing_call_20.pdf new file mode 100644 index 0000000000000000000000000000000000000000..61af8fc2bb8fd45728eb9edd88c6afe52b1183e6 GIT binary patch literal 5988 zcma)Ac|25K*e6S+Btj`_q7q>YW*FJGlBKbvA!5v246~Vq$r3^;C6QeuEfR@JcA_j% zmQq;~rA69A6v}(=45EJT=Y8)VGxt2_Ip1eL_nc=d#>7k+p`t0YH57b=5HM93)!kbN z2Gh}j!7TxbC({e21`=&S68OOFSnkY2Gyn$2T3ODL>^WmAfQcjEm^hHArzgZ<(g7S< zNJpPd!{L1ZCd?i1BvN!`Wnn~uuIzrKm8uoZ81N$Q4xj^e0oL~T03SS>Agiw@q{G%` zlWAlS4aO#uC=6}3t}Ko~bqBP;cZdv^)q~Wd6FjtSP0VJQz>%)37n4cThQs~+{Z;(c zRj71NI0B7E!&TMbYHG?Lhce?3g^6P;Qy6j_j9C;DfPtqIX-p!O0)tR-?o<{NRF!Mq ztN;Rj9-qddlQ`%EJRBeaWPrkCz!544_~I3y74u6d3>A(IDtIax&c@L|c2%w&kW+OC zcx@(;Ndh3lxDUrXLlW~3WmZ`d5mHE-grj)s%CeOSfCr96V#?}m2X*$O5-Fa}2z5<7 zjzog~)l?O9;E+iq;vXO`WdXJh{BQY?LXZR&&hu}bjBuWRpyqYb+YV6vS5XU=a6~Oe z=Bl$G23&ZK0~Szc!$2c=uy9ZcEr>OaNF;OO!I^|p7;qwCfpce_;1 zX21@>ROf@v3Hi}u&wQyPQJS+9YnVD$%B*SZ^xKI<%$hFA2CDz~DP>+> z$J(l+R*5`CN0rYX2_;<+i{rs9UoBSSB5D&RYHGsoY#?YVO=DsSt3_>k1qB4`osX;( zdZ49sVuNA<-zMea%R_=cr1!kbn97>riKXzFsM0SjyMMvWb#H(PL0o2n ze|b|l+P6fC*#A->xXwR(lGd zmXH>?Qa9Z1%+_=k++TO4-{XgD5Z}hoOJ6P6>jf}d&I;{WdfxzHqht?L6q1M%%R*&+ zv$>SxZO@l0+!MW~o0W$!(o*8bxC&iA5Y z;*&d$9%-*h#-*#0Ecv%>jE`)pJL~R^uu5)D=51N`Rz@;<-`({%nHz_n?PBM;UhoUTJ9|R7Ct&`wRK=K0CdkF1RNCYd3pCg@~RI{NB5M zixK$|nIDIz8Ph8b!`uvLvixG~h}#jeM#5RAXwj->$(t3$P90OZhjEwn-BEb*xj}_x z(C#2(*)vS@n2T?=@Df*CJ;_XECTJKQg;dkQn#U+M! zF=3Z#Y@T1lWYMf~yKzoua=r4`glT7X zQI7Kml(+DAHP*?am!#UC-!gIH{Uq-MC+~4I?{Yv}q7RfB{j4am7r5k}Q|n;vpkRy6 zR?GQD412rew7|4Lxuk~Dd)KcASy{Q|impi4+cqqN@A2zh9v)COCl@$HcgwMEm0g{r ze^>fm_aUiMer<=OHhfT}#g*+bz$c8YvzNo-E9()b($+stbxN&DC8jP#!im=2SG`Jo zwt6RcvAnFj>~6c<7U?oxhSdjW!g%k75@X$HHRl`pE3?kvN(NTdN!Izw?UO5R z*Uk>ej;a^OYrbZ__I_Qy4ZG&Dd0f-x_@2u*uAUvC-za<|eG6)(yORm5fUJt3 z%5Rkcl?fI5*-3%=ctd9yIOJ`2~e!)8! z8XNj8^ooUL(y_!_%8^Nv@E3Q+2GqiVT0l7r7AsQ%|7sI!g9&IWXfA9HPu#B*B1w{| z*jyqXvA$^AAfd4w)7o~SZ9t-a$Ce#swS#pR>OR!=MFmE#jk1tal0%vG9LB2Q%`Ax?OxS3q~C$UI&Z?e4e~6ti7R_ zvaaiWVWIb$TMB-5&paw0mZmin|Dd1?6H1W8VJg}IeIHG|6G`=H?reDxx3lbpe_(Ki zbH;Y6SJY^X+|Kr$0y_i!mAhHAXU~ET{{Ft?+L4YUt&zR8!}{16%y`|$&m}J^O~*~6 zCfp{LO|1OP>IuAnEo8flysx@6m1^;R>(8y!iGr?>{3pd@jl8dTn|O&`aYawVCzno0 zPdjH|^e_XC?bxd}rPsdw+T54*yY6$;h8VAn3R>TWa{Av_D!$Bp>s|Mu1OFVK(vZ;^ z(K$BVI9+(%p|be=c(d<-@6hr7H7{7JSS)#@wPa`A_qfU9cI{UvGlSpleE71na&0aZ z_G@S*(@!TyMrIEEnD&U9PwQI+Sl+Hzx<)~RpP!wl!wcS!T9v0+Rd@Y*`o!mDPf+uK!!Ws_ha4O|r9Js# z65cmb#(1ML_4!m7z!x08L-32RsfhWPk&f*!@iafg<(-Z{ghl!TeIy~lNz88rLx*l!Ao-Yk?F(h^vNHtf$72-)wyu9R@l zr{NCP8_Cl`jIg{6L(*6tAArHljg5_P41fTG&Z@RBmw7JDc`oQoY)mCl>2~0q5#U@vjS(;i z#TGp5EM#5R_#dgvyss1B`PvLCtdQD_0C=VSn7}|aOvt8f2z83 z_IZTM+g@sq7dm)lAMxhsSkc3$4Ij)ziR~rkif5`b(cn`K06w4$V1%>ICpk= zpu%1+>h<^6NI}Rw%1$vUMs`Wdy>A>}KP*v3Hs>qswazns9^tZH-gNY<&K(sC>s17P z*_h_8HT8$|Opsree-&29E}uI7RVJaZwJ^N^CbK@ZbLX)4zQVWb>TL(c(3MZz`m9Ov z_Ku}M-dZ=U=uf5z*CP+~6-_*PcjpsB0l%$Qk?ypjXvqv?TtatBMuOhA_i%*{<@5A8SZIDxu3HVXHIz zMaP%yt<$CG+WPsOdgs}@FZogKrqRhv_IGSmHnmE>hG7ylxMs_5YyJ#$Y2kxkp(?9< zPDf*`$~k_37kOeBW4` z@3Lr(`MO1@&Xb|SwIC9p%PazFAVKBLy;T}hSrjG=F*};O#Cie@ZZ*#B6r5FD5fGLk zg+gV5XmcpsYcGr=ajp+#3oxiGIv!xapbcb>Y6TF8I3p?>x>l>Ga-KggYV)K&Z*wC4 zs5Yl7&Yb~vyJkmrOganC{ke_+slG`qpfoAjpx0GWh=A)w3uoSt?d z1#CymqGLQ~{Wd3?(@^8eGzA+>AbG)Mp9A#ASr(AjIUTxruY6uU>|^rXF+|c z|DS-x?F6pXP}9L0U^6X%L-XT(=p6T~!j*6J%T9FE(hSkSYv;65^&g^b12Fk?Kg8hwwZN0eY1)Lz$;( zA^(G>2^P^`d}!1^eCjA9m}ran)KQxM@@Yaj`WK((zjzubjeqzwQ2)WFsR0IgF`fqc zUtN%@8vp2rM5u%N*W$HE@R;(4#-!tjB!DgiWs128SWVkC)U=#cHPtkbNR+}~BhG#S lhtd}Y`IcMIa64iE0EGgK4}%HTH77XWYE_}FTTS1=R7+x`i61{c@_ShA>hN0fGNPp zuAclbn7TR)ZVHgx=^ije5VQgz@PS)1TTi?SP<0Ib=*3#rx zXR0y1Dc&F(jOk4z(bSk4(pWs%6;K1)5Db^rgw&(r-PEk~4HpN2Jq>9OI-Q~hhx_{a z%KIwGld0}-1R9NoD=5Mh73IJYax^~@9m|v>(PUU0i!Ay84M!zV=mate2C-sY$qYKE zD%-q80eIXpKZQXhve@xBI6wrv0TP`CN5~`Kzs~@zSe`hM1mfi#0eF|h7`DyNHe|3$T|oaP>Y z^nZ$4F@+`ScV@OaD;9%I&+^0yba6c>csB+Xilr5cjwKMhSqsB@2`ACu1pEpwFHTXT zV5xLXggX4UKFjm}RRuN(h8h@~@a5nHJIk>RkU%|rq2L8ui;)kupgiJ-a)+HzDo6zM zo`otcqfnZeGrVaq2bjY0>a$|N;n>RlVh7GnHVl>uMx6~60KhR|x-Ic4|Hcb0EkGq< z>0q|%1IGzC!0Mnbn-gwGfZoC2hD7kSK7b?RAtvxy&UqwCWf3ulDY2z2n#N4J9Yeru z>=J7r`%Yev0CUo9l@Ni=eJ7Zi9e)TJzVH9f(ne802`mbzAZT<)g+RrEH! zX3{2Yee?4?&qKsoxgLdZ5<|EsJR>!dQ(@Zc`K2Ft)^M+Zai7%|>*Tm|QXRuF88V-? zWeX=VZJlz6QW|$@Si}H-87C=>Q$ZlhMWAxE^?+1dD2$KS61F#shoHxESpv_6*nXr@ z(tZ`U-W801h|rqtYf3r0c|^7AF=!j^4jnDM_h}KW$XuZcp$pm@Tb)~XZ{m)^ZZ23O zSsSCUaWaH!0K*jBB9v42X~2=G;>dHPE@!}PN;;5hYe@Dt6Xs@a%#N%4hj{C?5tjRH zV0-yR!-dmP>0_4Jxt=y$`GOr`6=9JXyDYc0*(r;f9aL(4;-U4OUs*i)V*e?5{n$*4 zw8XZ)4+lPM_%1TD@65@znmBBd0?~B!uB}n0o9eE*dLqo?n&UWIHocP)i#YsXGgj)> ziB2P;^l^jU_D&VG3~i9J~KOm&O7p!*rx1Mb(Vst9=@-}S!yzML;FN!A6`M1AXK zN>&PK^1~m#A21o+Jt{SIVvaT^pcCq%O_5$L%sh4bl(ep3`UOgaf??eDy}}pH%0I-o zO8e|9I^U^XX&Pu0s3(1eZhSH8?G8@D+Pw4h1bVcx?u?PGbYkSuA&=rym5G5#y~foR zC-l-W0#bO_aaxDnYr(Oea|yHT<+ps_HQ&o4b2ww|J>@YxMBe?|6TSszlA~%=9-oGHrS7!yWN$ z$o6CDiJ3jQvqqP48=glz+t>D~J+b}e3+Md%I`^FxLOCCV5H7n=YSJ18s?x7u%Ldog ziPibY9G1D$rk3fS8U9EFr}BpW#`Dd+U3MF<8Amp4kLtO0D=(RFl5l!hPN}n{-_+%J zW5LrcxDgL|^-J`bg0B*JmZByq4&SU={w=xU%M>7#B_hT^{IH)^{WfK zn0zah(&~HGCzrm-wLMO!Mfcs|gXc4I-nca!Z@6SWY3`b%WFD-hloXX@p>_$5vTt#A zEMY!3czODb)mv#s_Ps}CTN%+6!(~3b`F$xBpUTI3z4}rE;+Q-9lg5~D32$Y`h+~0I zsjl95hJSixVAWWae^qql5oTT`}AN$%f96q}CThAwzhcEE7F2-ls zVBUobKl?a`LN14lh2)r+#-5ESl{+0f1Mj>0eNZtBs0HLgVV9-K;NL7STVniM3!96Y z!(xu?4;CXzRcZx<9@1ANu zWz1=Uk!L15Dv2(dQcwl;W7OhwKqPeo^K?+X3za0lsqG49d%wflfasR$V{Ye)8$*-r7%Eb_dxeiyxE|LI{m- zlU3gvR4`gLbFL}MFt6(S+}W3n|K@DB2tQb!2@ifcH9u}QqV%|={eAb-PmjDG_3RGZ zMY?Y{?fMz$ZjNuN)Dl_94Fu*s#%lE~RH8)@$VvO}{*#5ZDxTzv_iqRFAf=S&r;a_o z7yn~=+jGsNsm8g^aoM?NSdT6mWdByH>AFNkw6J} zRfua{lra{220XbKoshJ5Lz`Z^s-tGIPHcSiLZZbv4L?02ZPa*$@z6NsfYg|n--92xWWbs^`=3{W%^9sENXTuRH6YQ$=eBdcm+GrGFs^Sip>jr%cm9P~p! zxi9dw$^4hYE^_(!sR$h(mrkXqW!M1*H`deB#nJ#g3_7b?!HzADQdu4aor(3xL^9PH zygUM|o2VWF2C-OyhuxLuUDe;_{Le!z8lw39EX(N~ZE|x6C1CL0$-o=tFDz^MTEVYT zAq=*UPe55X&53KiOKYapwuz@gLw2w;OCB!U(G%cTxlmFyS`ysTe_~-~e!*g4 znfkJO6xU%moIT0s!bs2-Z8wqHpw=f08;QnVRnpMl6KctQ$URuD?ucKL;-fBt3K*;G^z74-p8fbW zJG8@VoqQh6g*h*5CVsK}V_M$kQXWbZ&!eoz?Pl7_YAGgDrzf40&%B>}Wvk{8@o)!h zbW6^qv>P2UmdD$5xA~9R{_|)`&D3HjM)tXN^b6VK{_{spXz3a^7Rc{u+8^u2DbrhJ zc);`U)3aPyee27)sB3EZfDuj>LoF66l~Vn z*9w(vPS>7{<&%mL#a*$oE{f?uSnU7dubo|@e85GDB#KDzzZtgfxpL{VKJ6DeU)of8 z)jqfKD*K+vK&;BV)pLcci+d11y4JqM_Gb6Au=1%$(TA32xo5^|TFOKV+HT>Zc2+1+ zoaWaDMaNnXD%M;Mvv)Vy+n7ZADlr(tbC)B#)-C7TM2=6V#72wLMKZ(ofy9PhrJ7p_ zC5PVbu$hyeH|OUT4{s?e$n z@wTF--(y>VVTp$`VN{eCcFCdVrS!Ge&nEq517@S{k8XSH6W;eeH@X&P^0o9tI4S;>`)FU%UbQof>w{*>Q2WaekUD``nv)CdaE*%nyOb6MP zSlAb17)#<($;t|#kr`ARK!ZVB%o1t_;0ah=G84LZ%PX*+Uk$}&=vQk=#4pvBbj7;T zz{1#K&zeqU;OJ~UXiIl`a62Q>p*j%^+OZb5pkthPm;$TpTZP5q}SeK*y z9_?)Z>4BA4BH0}rw!(2t&{%#27y`x5j(6x6hC(8hkT5sFWefqjm-U9UjH#l)b^a4m z1wY7tU}%-U#wnptpx1vNr-V}ddz^|Q7@2>JQ~8@u8TGeZWfcW5t$v@Ytn#-EWi?`e0h^QC3uSR8Ub=MxvBu|LCzc4mcFY jFvz#;%!XSN`~hew!1bZg!31Y54ibe>X;hInQ(MInQp4zM(8qPMLRi5cu#SVF(!6 z*_{^#Q&)$7{rQoCevx4 zs%-NX1mJN?{9belk;RV3!2u%R36N-1I8qJ?UpWJ`VrdGAD#x-x4oCKcGq7IZa0J^9 z$f@dhoGOh#BLa|N?1yEZ4w3c;Sx}ZpfD}?CVo9zV5)4^9;DV(SX%d?IK%HI51d^)* zQbGA70S}O&1`bOkLjUpzX>~Yc88V zFD!+oiByNL=(9ZkUsYg(V5oty3113Mu(K4~014E?2MS)WwGjDW3(6y2D0kQirL2U6 z-m_4JB@{|CbGj!LW)DLwtv)LT?2j++FLdDSWW!)7VANSt000~VrrRQ~;tF1HX#ole zO9Qi2A2>5tyQqC)(lot?lm;zhMf@zH8l2`&} zQiEGMU3ZOu8eSdQXzvgv1nh?zoB9N2XmgdQH>Xc4^8K!3G^_8NojUNl?$ zhK&|))^KxMJDlO;eWs#vVcY&fuAQ{cW*vD)3*SDtRT&uYIl1R!>aUD>jw>WCeFP<& z=Sk)Xr^9~wcwzCW)$1BV(B5UDg#JG6fI6R$39`@D;>w6O3HAKH1ZdWew@r!&*;UVD zepL%IX8Gibleg5qu^k%ZNz;xO*(UZ}w@jQv9sOHPB%r=Zc!wZI?GdR!*I5Tyq>)XM zjPXX;^Js70wCG?jRP9WWF~K?X0N~B^|4k5$`1xjaXywK|u7{?L#4S*9;&#qwc1xs76Jt2Er{~CIy zUK44nw!V4fn)V=(7Otm3oWvk5uQj6&w@rs=Z{U@9KgB%wNJE> z7Bbeb{k)sQgfdVW;}+RD?$%tl_&Y)>LZUMFSnOolDsDDAsL=A#P3t?a;+B+4Z$stu z#jMwBhBKQ;yIsh{U9z9apaL0 zR{YNCP9vhkNsZDCr+9k8zdWAA9xQ58*>2A7dXD;t`<;pkQclokgAcC{=j+Sc>H;1{ zf9qy!s}j`Yg+Kn-Z!)%bOnmzEEOnMoC-{W6m&9rzMrcW>gf4%^MXv~iVf?QBLKnm3 z9%Gy(yblybc4}9d`WyM{NnE8FU%LKYij%NDHNZLNy&}P-^{)m$qFa)FuOfGb@;B4CEVS+ySLnPYKa-%@g46cTAiesos}_oQ<9n6 zI^2=KRBAn*k(AYw^ULURPJMes+X3cCYf|g$S5CJc=sa+o59WLnM7VOo>tT9*e|5%H zY}tT7ok*RxfJs2pzNYF}jaa9GfAXUW z-1E;B#N^KvQ1g58=Zldg1Krl0Z;tER4c&E{$b4l`==p;9voy@}YnR2B*zPZPMv8wq ze?0*&Cf`Z(YVis8&Y^8}ZjIM@uKVH0!N{zegD&+a>o1#6nmgZAFb`B!NRCcEta=%a zI`-Vj;Vz@y;Pu%-%l8uW?8>KQJLoYL!)4xYZuO>CjFeBj@#sxE70;0JOCD#uC%l&) zCyx6!Q=C2Vbia%$|LXB-zv`H(ql~yyT9eEl=cjU~62?m=j(_bL4jWtlt!G5}@hd#F zi~f&v;M)0%zk4}{g02LO2i-I=jSG*xCwn$-2Ht!B`+$51Pz%Tg!>)*z!M|BtvB3DX z6gCw#g~T3}2^1lUSM4g>8!A@3X9(X=iD_=hY#G@6^nlcXirS&N%(~CDZ^KTV-4bRZ zDI?3PQNO}B4=6I-a;k7YuNda7e~!Gi$tyH>3^;vpR_tZs zU1WUxxAyjv+M`V0of-?0VPGx1p!P{)bGTp);Zo#+@m*ViHrj<6L56O z9O_Hc+|9e8!$n&(PyW~w#i4@~D`%N5InhSii~NS!E1P5KD0`%Rd;qmzxcj(ATH%D< z)S%yYztNf7{HohZNn5)<6&1N}x+i_o>a|Pti}IxU(rFU9D5gw_FhWM#pr4@0_s^0& znmV5MMyXZw`kV?#bx7Sub_<)hB&o(!<5oN6Bil{)di~np@%N8ad1qSBG@pG_JECPf zkD09dXSA%h+F;TkZ0f`m&lKM%z2{V>Z4u-6*r%H8Ux_B4cK_T>o+|7LENCzN-oW{e zvyqd~6;=EyWM=Ku_F0Eij3#Elj%k}~QJyzGx9e@j@4C^jZI|43NUMww=k$N7-rslY zgL~cQR$M18p+2=EwB!41!)(!Qo9fc^$tLds@8R?Pn|kR2boyQ;bCHg^A5k;st(Z4S z^Fu$ZJh-wlZdqg(^((5#qUYXyj89wJygGSUwMo6_Tf`%Hj9L4QS(hAN&k1W2-H3Zi z#U)>p=gV)SK9=5al0B{Q_I8`2x8qNLi?v0P_i>Z873*Zc1q>Ts<)K7--Z)rl}Tm~y5?TBd-V1AHx1Z~ zc-HrL21NW)o#~x{za6WfzL)zodNCN_3J5u{<}1H}pz+tS(TjbDYvyNkK7=F;$O<9_ zCw5A!?+?fyE1Nmr7;Tta{e3q4b;FCByAFpPEYE@mHc!t@*p4bZyW9G)yLsfP=hL3O z{(DFdY=1ic19UefG*)Q|&*%69v!CO%dgrUqn~_SB$G-bb7S<}elP^6e3FuK0SDc$Z z{;V=#>gUdO&E)BZ+0F^+*|v#<{N}P|z{#}cUI72}j28+xIjJV-{AkjJ`K3Vo%NJ1; zpGUC=7|a@bW`I)2JS$H&D}DQXF}hrx~Y^mMUQ01t!Cs+O?hOQV#RMnPv{Ju;C@ zu>voT0P7~IhlD{amf&G``FU4m#hm|ns6|5*E6=i=o-ro3hfsV59~})mVSYl=7Vi+g z4Tuof0Uka@p>#*Cxh}1lme}{JDl~E|#Ut9^AO11vxZ~?Qk?jAauk?Q3gVXc#Z4Z7; z)$a_fCOefzjgP61mrQ#Wys9k8dF?#k`KmN+OW$O({b94av;g7qZ}lIH55<0l-#O7y z%#Vs48qI1y@gZ~XUAe4AT%WDUU6di_EIr@kb9Sy>XPIp@Wk%%a+Yi_GB--1WSdI-0 z4&<7UULs*H$}iU&;qV)Mbu^4$K7qGwdev?b{@~;KcIyj1BEc^urHrQ%E$AM`H+szj z?|-^h`N~|=h8XJTF34r$Dip5kmn&)NTDsb3@)@Ew0jnrXb&;dU46&LzP{(kI=X z2Mefu=X{ZJ!|mR~eaR=MlUi&M3a9lV-ab2`rlzCEW2Y0TE7KCUwlUKFkr=m{fL*2< z|HlqNrVj(XS&mDHf*ILvygC6rmAa8c@LIoNKhfqw)$euzHBZaJogq?f+$npQLwoAF z8|6#FF}6IR7rcf|&(wOOJByMcj}2pX1n$WnyC=id+868Mw`;U8}W&} zXr8QV+gG2XQzrY$7pvU$Y>p}~gAU&yd(PKSD~};_<6MaT25;ZPTOyvkA0zy#nya2` z?3)(M8V?WpFM9%%bLuH;Gr8Z5-LAIdjk6^sz;`iXfWhLZ}H~q z3Q*Z8ytuuvX0b&;TskBYnFg{gvas*UFqXu{DwZWcCDSQ5fC__loki3Pz!R{#WCnB> zmqW0gKMnaM=uc}=#2?ibb;UYU!CKiu&x%H&<7jL>sEgNpaEBw&pwbZx+Qb%ir6rU8 zlno%0Ffb%kF<8{o3Pivf#sWLWb-{0ovRUOgwoC)CJO#qbDg-Q|Kh83Nyw0lcEqNUj z#@d<}l?RIlWE>r;a{d1VtgJz>t%fQU<^Y3c0{AYi=btyQ<;JlzVgXAUvE9qI2x77% zlObJ}TlMG51NqAgOYtx!xsX|(4yXfuZooAFpegLoTC7&WSP{1X+7JLAfP$d_E&y0w zfuaK<({IT%!RTQC9xmg=Z0qn+(PJ+L@SB)fvcmN||A8q14-AyK^Sc!z#rC?zEY zC728U5{3lb%X&jv!cKQ~o!f zqB7!N`Y9^QgPFZ@uA&M8jH{KH5&{bLzc3`?-mKoJ*r%2}FRx3x$la zKA2Yf6y;SM5X$n3O3Fy-zj~~V0}jP84Du~Iv*A_*KLA<^aDAvWFu_@iql8jG^6uVk HaMtq)}lAB?N5s3c!lxB}A$c%LXM3$sfi*k%8%OwjH2T zb+8z18lFbLfrhakmU)H*+8<<5SpptZNSlBndh1Fv6tOrj6rDhm)|2x_`QykatUE$Q zLm4iw0|PA~;Qy>=BP%F%V1J7R^#Fsi8dKUq3I!XV5`O~KmVr+ zY!C=6AQEBAp$H6?BN;~o^auh&6?j{WbKnik8VHyv?DWx4Q31cRP?cpAOe!0?KNac* zg)i?lYscL@R*n}3Fm`GoQ4}D?94R;)Fb7DkC0^B4yujAtC`1$u$W0SmARdFW-*3d` zgqh*NZ%~*S0r+f!!;r8b6Ywl&xSG1gB4PtoVM|#wjgfvY5s%#5Ez&>=nmVV*$$6;0 z_M~+pN6AUWYsVu9S)1ZHQ0oOZ)p-cnMGBdktaUe7XS$6{bHNG<+4ZgC=5};H&IkEN zQ}c|(o+7Rtw2#(Zx15V!Kgh2N5Br$j`~K>$%mt1ML@pCJC5QKM))7zJU=ysc5VYk|03_p5Bw4+F zw%7uXj^2w4Xb=637mNMbw>G*;XqWea8FNWH^(4td=tFw)Mu|-8%}ttOC?4V(o+ha- zC_(SdLOQQlBZq%Mf&T*Y>VjX>GwjvL^J}0P8w@5CZ<}1!+F{&G+-hKAb9UYH2$43f zClQ>42rlxvuXPeLQ3iq#>4&~`-0Pv-rwl}1ag-g`L2^t*%wOBKjZ^K~M%4(FYuu$# zu>+8DPGS@%obUP(zUs9O1Cq&+P+lH8=$`BA@W$&dh+(-9QqGMMu4}lBFCzJb1=dTg zFXil6x5eNwQp=IM%TV9={k7OOwOoNpfpZ3%+dSKLZ{@y(5-(UUQJ)CkJQcw;fMjgh zCUBGaX~3PK;l9q9d2_&PMmm&hdqmE6ONKZ%a_42p0iMSO2s;Hw=pM+Hm`$1Lnd5dj zxxS8E`TSi`l~M6oyXpMx2*n$<5&7Gvv;tvh`ltfpjg{Jpe)Y=|1&P4Lbf4wYsCb=Zd zet(6@QLCTO{Rww3V4BB<)te7Csx|*;u8H5>DA5?wSd{3w+jCF2)9=K&>uU@jA|rF^ z>|R|*W|D1C<|x;T`96hPbCa`NavAnxsc*|S*)$=W+)m%Te2Zo^8s8ze#k4ECB-j0; zx-b6^W%}8ZIb!XvN=;ljzwCB}`5!oB(e0#VrR7#(^s~Cekvj*STkmAyByX>kt(-fK zk9@c0Jog-Tm58ds2hZ<^>6!Uedpy-V@7d7}eq0jwcqwDI?A|UYMvm@rHOZ@x~A5q;!}ClV0atfJf8|bS>FU7 zx{tMw!#$6C+&!{AqNSc~38UL5vB6?BX?i)?nL{^a+VeU_yHeWKIy^GdvU_uXnV-*X zcplrixBXK`TF1*5p7{?99~@qYPTQ?LF+cmS05$SBJ~~U z3u4>PTAAr$9vMAGpEiv%jeWe=GOSsyxh7FJ(X;S#L42Wa!O6meg84#fL2toA3F6*h zkK?O850gW~cYP+ZUYHj7KPCJui}C-~ZTBUy=gXZ>CBM+$j=)MtcQVLrL8k(8Xvi`lgCaxVB3ArF2{E^DuSS7EkxPjOV5=PYl_QNYitw zo|JE=CsdA>2lVClU#8@~5`(s=X&OYNqAmJjDyIQP4sb2#Ec#CXI_ zORJ<)iKU7sl4fE3_a_IHqj2>&#YpG{$#U3ty9;*6;I^XX;^wGCXN7PPf@HN+`R-`( zl3l~t#wuiMTUOiPmM436?yamJW@a%z*1wJkIUyQjDWf2xZq|3o@w~7}nb}}geU@+b z4d>vZz6TVA9wlv9Fgc+;|MS6@PPd9|4u>5(Hz)oq^)4bg`FrvuM21#my6-cZ!oD)) zz%$Knw-3|~S4SeX5h zj9&YjKN`6A>m7XN8#Kfds)RTz0I#JQAXU_{h_$n zcXO$HpuT1oHT)-%mXp?FEzVOQO+%8`6x zCgNoFweREJ7ZRk{Lnps{8G88lk2SZBcN}j$(O3UT-(>+g#r*uWyuZeD$~0#B$TaUX z-&cBXNR~@6!(;42ZO*S$%MY?YWl7UT-Qk7L%O)E+-*Pr_;=AKZUPR6EOmCZWzlzjD z4jyWE$+N4tH9jx(I`cR4Ym7vk&vtpu@zLCY4>fz<~c5SLTU@&0x^uXqR`bIi^x0;Pe7xPE_>}iMgo5Y3T9}a$8*_ruvImH92nu=QU zZ{H_p@U*T?AJuNw>HQx25SC#5{KlMD?os~xe6wBPlOx0Iz=)8iza!GUu78h7JDqbrbFiM;r|N6R_GpXqCSOq1oA^Uy( z!K7PXUZ&r^QuVC*HHG=xY{I%K&H6$2{EO#)Z+b(U2c16oH}v|4#s1Qs?Vp9c9;>8| zDE<0+E)vHT7PWWXH-1wAi*I9J&%Lp&U6?g|7nL%oD1Z={*ded8C#+zseD-wHC9}Mm z$+=T68=u~kvW?kakqrxPotd9-`Kt2I-H!J?t)HIwKk3~ax{LV0Sg)F->imqyKUFEyKX*LWOP^_+do>|H z*Ex|=&|2P#^R%ih4db7gC9C5Cr}hb;A5M9-e<_sw@fkJ!me^@{H}0N5*P1t8q(8E_x=-?ALBmy zk4vXg^<~%%3bQaaHbPNxSSWZ_wTF5v&(c_)1)hnGNdywb0k|sSSocn21QcYk2M)U{ z&%2td*8HD`S}l-b^;wqFKe3r8slj)0dP4ZF5;Eobqu9j4cAThb#x+fYwl#qfyN-qr z-!$7VBa?FO#5X>YzI>b~5bN{57!NZVUJi}ihrRjzYqE8y_vf#SqJ{+?QSnxbR%X$s z()k-RQO1^8hVO^wU5e%zGqW?HrRa~+$4V}n-E-1?b6#%eYY&^-Cqi8Ob~|uF2OobP zcJkdkT`8u&@x`X$RCW8tWPW*9)H`T(Q%;52!y>2jvyPn_)2@R&FAj@4Oloqa9K6N5 z^@LkcXXhCyQ3>-ava@-nxs)$>aar+^kV13E=B(MfFI-a(ehV|Uch3v@aOH-i!2UC0 z3F7hN9d6Fkd7{j;1m9;uw$D2pEjRnt8h&^iCoYaWcsU|k;=pw$DO0KEZ)Nf?9}ej} z<7j0p_*OB~Pr$kE`$mnt?EC@VwIex3!I6_61!>Sy&fn1U>Z8Z*YTS8|Ug@r2U1%xKBUg82Rrh@rz#>2Qak6HyL9c({&TN)~->lYKd=b?n*l@phH=3h8;)J5oy z)HXKURwzr2F>F`bs&bt|Pri0c)4qFM)6H$m((%XWizp#llQVm;wo_2f1^6#TB0 zbEd5?XXL_d)bFN*quUmY@MW*RA2u4|XlEZ&`w%o8cNr7u9(PqBjbMYAyJ->*a2Y;D zRytD84dm#N&$Q+0a7zLVFvQ26!7cUHQ`@!1RYb@Ll3 z&_AaST0bojn6Zv@dcFZwQzv}ui45ua@foic+s+Zi*uFN&EgCh`2IJ0wFJ+@N>>h03 zO0^Re-!yRF%!JO-=OPy*YPsOiR}KH8R)D$4z8Gt2AeM^&0=^7`RlpLD1#iX(un7g$3icJ% zm_#SipoqoM(v8>~M`fq>QrTgxVv7K|42eV%4PaYhVc(&lEQw3KEPEW4M5kbIR47=D zmQZUP7LPI_F~B>z5}ft?c~M@5{=6-T_@mmAt|&AW=$I{z9B33ehQ`)|x^(>qDj$&s zHjtoTaa*ib%O?G4Cx9j)p$M>(u%xF0fB?OXMRuh3qTiNevzl^jnWjLK3V>I14p>Bg zoMj1moz>-A_BtSpRkD|q2bu~b3?1xs{r?24?oF_*20IuwI0nrUcXW9_|9pY2G>)Ya z3s}~O?OwJ;Ad@|b1nRQVsz3iopuen96h8~17m4+k0uF$`Az%-1;1YIdE%hv+tcY6# zo$$CI90f_idEtPz3m6?BnF*dsCZLW2PH+S}b$<~pi$PLISULviwaA&_z5P-0Y)+Om z@CU|T{8zJX<)mfZRvWr{H>`jr9Te=nEvk$J8g|sxvCa0DG0>1Dki3CuE8N5YOoPCo z2z3ZMy1`$lx|*7b8q|w_8AAZhWPKqnW16bKzw+OhIuN*jVOnbcnx~?!3hd_Uc`EAa z|DLA-2O{UMc^d!bQ`G?Tef2z5py&24OcM^2p4Icz;L1SV`3pmUmEkW;84lEizc3Z$ z75dRAC_Dj2fq(&GVFDzPoT`e7J6uBZ_Y VN&^y_wLNO;2rY=Ltf{Tp{{U8e$TpTxk!HCVW-|+uC3_n!$Wpc>+4G~#UQr>+ zQhu_PN<~T`ODONXGl=@VpZC3g%;%o(J?Hx@=XuVY=h=ZVGEqb*sSEE21|MMrOc_SS zc?!c|+S)L<1we6Udcagb&=!Qi2X4p0F^|yz7~ILyVh*zBj4c5smVjkqK~P6Wn8Bn2 zShBFTE}MqMdjU)s4sa(@_R7e>h=jc|jz~*oOPV3zK{WNF19pB^_IN)pJenY*t0Sz< z)?|}uWRMNUCX*-(P4-?HEP;vxG{JWWhRf(c>d^^qnzlwJbCbZ)UKtN2lcouW`}+DS z`Kl^W>F#g@8jXf4tH4!M6u}vajAIlgmaRx($Z|O5Sd0J$o=&7OiBt*(zKmy1Bg~@;;lo0TxD?lq2mQWZ<92=DIR5F~6rGe9xxpqKK z)h6IInM5WDfDGe49P{)^%-_hIvLqs;kR}OBao;P$RwMv!SQd#Xqq7U|0pPtzL3

zJH5!_fSj zmlJM6gucPxCM58)5rC%>ASUox$Z;e}eGajLsdA;vnZ{1O9Z$rp?~tga`i`Gf zpJ-^Dky0q+-^%=C*_P*6`08G6c~Ib|aA~fZI;_85Q~+}Um;Z;ue^Rdn7ozG9z`rFp^P4$aQUJ64qVRsfM|udGJ@zmKVeyme(oyLn zHksL;_WZdbZDD0$F;{omY;AE;6Sv%_+WgEz_q(v#hLm%!!j+5?GOVv8we<9B^{@Rd zHnsaiXv_UXY_c-RV%g3uu@Ut(7jd2l%fyC6-o}j|q$MH`Jdngn|8xAMDM`j>@0~UN zLS3i6JRHaFD|)W6*-FIy1ml6gTMZ3_lBn+*UtwR~_VZFTf%jv-b+V-@M0JGW4?p&r z56cZpPadCP%&gK6IjTpKS+Qz_- zmL8O8bFj~&IJ_b$Ai3MD%KErrI%bvp(8XP6 z5{r{;_mvtQv-knq7kBdlzG1iz)o`E=*)Y~n86#IGRp(z<81E|Qsu1MxD}Lr0pZ)_( zNalT;m)9`qG%Ktr_E2=LN5RJI#H&u(Y}?_>Z%fu$)nn=ppU%3N$FvxTY277m+?G+C z?fePlDKe(QiaL?GspaJ@qeHx3tAr-JPpQ$B?e>OW#Hq$!)(Kzv7;!d9^7-XMm#Z!lFAE~!L@Uo6k5aE4 zo^c*54@(cb+b*{SI(Kw#xaHa$H?ZY9!EaM#l1^qu`nxRImYmjswo5I@R+sdojIQiy z)AQN2FCw4sZW(M%YHk15HTRzWy(6@s7p6|+cI<3EM7E`}1w(I&oIVr?YV#I)=>dVGg7Ds*R@|!l}hdh+j z3Q=2e7dCB)vM||;e`xRsciQ-zapa@j=79~n8Y<)W#=91L&W|bZ%s){Om;bYXk>8a+ zTa38@3<#Of+StB ztwb(dvUq17p{^X$)O@x1jril;+jo~$_tjjj`BeStq<_SQljgE}WKkyFr|i#*8Qn2? zbG7=aXU26$zryZ&^gW$Qns7f_Tubif1MLoZg;qxbkDr~9e0KRJA~Eq>Vk{yJ9g^(% zjJZeaj*8EjhPPXKtNKbu_p{drY&edXJ(g_l?A^_-FrTTKJiY90cx$*BuQ^7EozkDc z-aZ^?d$e`)S`S!|mx%+EmYcnqN0_K|G#?I*d4+7|19X=ydT)D;zyI@y_qN-_XmQiv zoVttZadPyWtX7MbfR?|nVke8%-X3t|*BD=3XlrOwM0fR|uG1`Lyyo*zNl&Hmxbew} zqZ2|CtA5r>GNr z`#w`QQ*^_j^3Ij<2JbiC1E+h}_pny8SaL`!iME=tn5oltEm@S=zA-y5{*3foo6MqK zH4R1d&$k~F(*&EAB@bveXm@>!d;pKLd~tooE&CXG)ZW}6@)olA_SfXu(i^CccdolC z9^d=w#`7cIM}7p@2o}lS#gA8)t$dzBOo`p_4t~z3U_i1;%zJ<`F*5Y3fj6P>$Z#n= zr#9nb^?`)EFYU=UQp%rIyrS3qG8wfjPqMt%@$=soUaz|X8s0bzl54xjfsxaiQ$17g zSHoqD_e#@4XF~w~z_8uRzls=(ntdG}I{VtXYIaKhL)fJ^ilPY7(XH~@3W52+Uts<#5Bd!K~*HVz;sO-?E1|JT$O2EH0z;Rs+M$ger=R}v=ht>ktJ)@ zx;i+j#2Cde*C#xb#iuqtt3oW}apb$7aJ8f3Qf@~FylxMshKITTm%v$}7TN!}>>?Mg zpDNJxasF0{T7VD3;AVz~23Q6_fI)XvTbRqjEcJz1(4E+jN}|&3z+w^LRGx+i7{p== zUUnDXcQux*`9CkUXozCzU6z+@uTPOetg09kpAJ#DW^|^n2v%D zmh?UsDbqj%qWszk)r`QhZ$3Y4Qor537nju(^g2j)w)^#6_-m#2)^GNY-fgi7(99b> zn1?qCFEltonl?wfPCHe6DSVVWwzGh|$3w<=%r;RW&wEtxV(IwW$AWHRQg=HIq~-YV zz6n)dBK(2t+bYsk1|RQhGroz_-dR3&D*XvML*(fYy0SsD<&^V?<!SJaPZ|fh{1h|=W))VRS`1<56T5{e4MQg@yZLLW9pyexJ zcK8@idGu2p`%uhzdPYD>E#jzRRqG?lV6vEp%%rr!xK>P5*30R=6vj>Fd%xOv9vIV{ z`ph~dzCrGM&PT=7zGXSnPb}9prSRxyMYR)B^WYmCSIdps3&FZkBgQF`ZWg;3Dcy+o zbw&o$vy?}-XP)?D$u`$=dyJ`fjU}@uj4X}m$A>;%e2}gg6HT&F)ZjDB@v)a(ujQFl z8tNco{=Aixu(8C|A>zQ5KwL%$ThQ%Aomjb=(5V34XxKU@@u;80)@bcjqgqqWyQZ(4 z$bGBGlCW&wjCerq7ypp6aSbcNtN%HF?EaPId@Hw|X*{Clyv2my_v>1{irBZ2VSz>> zA9tus)AzN-ujSkM(DWG(uuSo}cy;qu)6OVfKSpHD!}Dy|5KOP@laGC{U^7H%~O<4BzE>(~Me zDvOQ>7%(U==TS?5K*SnQ*-*8rq|AAKzo;xgzu)FX{8nvVS1gVJc8}&pc1$`8&*bXC zm@kCEGl0T`nkg_S&FAuV!KB}XHDnS7hJb47c|Gkw1g!Gs*fH*New&xgX;5)x8iNfR z5MES6bBKOB%N+7Lr{lHYbx;`R@S0a1EU&3}7S#9o{|Q)HrE{%@YI!Sw%`^v&E$rv- zFR;bNaWvup3mS3V%e4q%vZYcXT^3vQ`)r2%Wr?MGnNi%RoWm6wfCnRSClv>*mUrxI9ruGj z%5yn6(x4wWcky41tHsk6v|DQG(*3Xi8&)u=4>hMW25eq2mPR+%Uxr|Nl08HPX!bK@KOg`tp0RV2(!WC25f?&N%-EMOXHV3_`ise@Vk2Zl!eHBS|#_7|Tj z3ibCqb!G5ha4Dav`rmwNYA7&km(EjD(*O^eKQJWfFS%;!>VL^l(?I==p;2HAF6Bci zYb>&tNyidN09_ag5i=t&jdrQ2syZvHs~|ubs`7shIY$K?id-1vU2ZPJ?TCH=v>D(I VF_>UVbG8Smstz`&cNkln{14ac>%ag2 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Resources/Animations/NavigationMuteOff.tgs b/submodules/TelegramUI/Resources/Animations/NavigationMuteOff.tgs new file mode 100644 index 0000000000000000000000000000000000000000..0fd0c192a503e3538abc1978704508c5ed39c3ee GIT binary patch literal 1246 zcmV<41R?t$iwFqtTjFT|19fg~b#!GeYIARH0PPrEkE1s5uS9;vmOrq8ytV4}o+_Ps zZC|3OqFMGrlK=vCd#6+WduNORL*Q;#ZC5&NwF<`bJ>!}2u%F2z*%Hl!WP$|bz9w74 z1Cm!{3rh)020M&B|(NiTPz6k(OX7Fk6qQ!x< zT8kDKYb6R#52&#)-sx~gO05}><3Jk0IFADk^4k(s1-#qj!^Zcfm-Yn>dZr!E7>0RK-o+wv3%Um zks3#eQp>I~$ATB&T+^NY9~bN7tbk=#z@aPP{7@E9zg1dig)6P+mU4&V3u!w#%ee{c z5)U4)#-Ri6MsJ~0w;|5#yrGVXcKYagY^ILXk%X;%3ZQjt$+q!(H zfZ%vHh;UxO=~}^)Xax4pMMCx2etU4?)!qj_ikYaxX~3Ni-NF267n?!O zL@55W#Dsa$q)Qlm9RiaU&3##42nOA6CPih#cW_nivdGofLh{TreSb5;xQ=${I@EGw zQ`5%wGe}R159jQqx|@Jy&wriTImF% za-m{oLU&={X$K{ABj98k@o#Acac8Z4%gg$e4VkZN%hC?=B_w~&-Dmm4O9&A)_c&4t3_GJYA{|)>~`+{GFFVh$H_z6^>y8l|krh-o)4A}MhH_&dU Io+lRo04U~U!~g&Q literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Resources/Animations/NavigationMuteOn.tgs b/submodules/TelegramUI/Resources/Animations/NavigationMuteOn.tgs new file mode 100644 index 0000000000000000000000000000000000000000..7d3d18b9fe428661193be5b69957ca2a200ca7da GIT binary patch literal 1237 zcmV;`1S2IpUTa(RZ4 zN2L2q*3t|4xvEzJM6``19bm;5QsF1JYYu>Bxb_oF_$4BZr*TUI=_Mk7x?xmQc>gVuw=ddb8SC8SP5ETL^QNh)yD)KZAAn+VBzgfD2ygR*&*#cUX0B( z;Qu--?LMyy*T&Fg^05I=%gzX+CAyj9YRGmmo^(~k^OFMCQUGph~a1r;9{7- z5Ai#)zR!S7OsF^QVQ(KOJGJGU{v+reg#H~B-?REJ{T=(kN?@5>#S z?YL&`?oMRb#kmu}n8p4nryW$f%ER6F#dvKMqYetJ#e5jVO@!DGx|21}Lf3=CGYK@!_U+9*#&@-y>r(U0O@__wCy<_> zKOT#h>TpuLaEsgL?YkVeuWKF(2rSIo_f1t7O;`HXSDqhzP=Q|EK}CQL@St11TbP+c zQ;iQzUw${uarvvLk|K)j(1Ta#ue$59u1EpAUU$qfUKlvRG?i9Lk3r517jcDa2Kaf=9(CP?)_`61(^A89uPZ1+I4Mxp*S~{M zo^ddpYLN{wr%7rrSTOWR08?Nc?F?jQgr5-xLJ)Dv*?{9z8CXSCnvD72(ZeW2a;(!B zKa)zLc9ZH6S!iMJe5vYFES?h{&sh=A85_D2FL^x^pg1sRgbgf@M?Uq!CXV;1EorLL zDAqK|Y)u=g!Qxm@m7(4kQY}p)Nkx_-2rYoi$WXy;{$*5yW_W5S>8L3@0f7h22!N0= zloG0#7%;I;&-t`RiC?s>|x2uwD1a&T^vXq)zPMUdY literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 3746158718..5513e8fe1b 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -45,6 +45,7 @@ import RecaptchaEnterprise import NavigationBarImpl import ContextUI import ContextControllerImpl +import AutomationBridge #if canImport(AppCenter) import AppCenter @@ -1688,6 +1689,13 @@ private func extractAccountManagerState(records: AccountRecordsView, options: ChatAvailableMessageActionOptions) { + func presentBanMessageOptions(accountPeerId: PeerId, author: Peer, messageIds: Set, options: ChatAvailableMessageActionOptions, reaction: Bool = false) { guard let peerId = self.chatLocation.peerId else { return } @@ -325,14 +325,17 @@ extension ChatControllerImpl { initialUserBannedRights[participant.peerId] = InitialBannedRights(value: nil) } } - self.push(AdminUserActionsSheet( - context: self.context, - chatPeer: chatPeer, - peers: [RenderedChannelParticipant( - participant: participant, - peer: authorPeer._asPeer() - )], - mode: .chat( + + let mode: AdminUserActionsSheet.Mode + if reaction { + mode = .chatReaction(completion: { [weak self] result in + guard let self else { + return + } + self.applyAdminUserActionsResult(messageIds: messageIds, result: result, initialUserBannedRights: initialUserBannedRights) + }) + } else { + mode = .chat( messageCount: messageIds.count, deleteAllMessageCount: deleteAllMessageCount, completion: { [weak self] result in @@ -342,6 +345,16 @@ extension ChatControllerImpl { self.applyAdminUserActionsResult(messageIds: messageIds, result: result, initialUserBannedRights: initialUserBannedRights) } ) + } + + self.push(AdminUserActionsSheet( + context: self.context, + chatPeer: chatPeer, + peers: [RenderedChannelParticipant( + participant: participant, + peer: authorPeer._asPeer() + )], + mode: mode )) }) })) diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 3c04c94421..448777c9ca 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -2232,7 +2232,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { additionalOffset = 80.0 } if let _ = inputPanelSize { - inputPanelHideOffset += -48.0 - additionalOffset + inputPanelHideOffset += -56.0 - additionalOffset } if let accessoryPanelSize = accessoryPanelSize { inputPanelHideOffset += -accessoryPanelSize.height - additionalOffset diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift index ee684b7ffc..4e0f3d3898 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift @@ -198,7 +198,10 @@ extension ChatControllerImpl { animationCache: self.controllerInteraction!.presentationContext.animationCache, animationRenderer: self.controllerInteraction!.presentationContext.animationRenderer, message: EngineMessage(message), - reaction: value, readStats: nil, back: nil, openPeer: { peer, hasReaction in + reaction: value, + readStats: nil, + back: nil, + openPeer: { peer, hasReaction in dismissController?({ [weak self] in guard let self else { return @@ -206,6 +209,31 @@ extension ChatControllerImpl { self.openPeer(peer: peer, navigation: .default, fromMessage: MessageReference(message), fromReactionMessageId: hasReaction ? message.id : nil) }) + }, + deleteReaction: { [weak self] peer, _ in + dismissController?({ [weak self] in + guard let self, self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudChannel else { + return + } + let _ = (self.context.sharedContext.chatAvailableMessageActions( + engine: self.context.engine, + accountPeerId: self.context.account.peerId, + messageIds: Set([message.id]), + keepUpdated: false + ) + |> deliverOnMainQueue).startStandalone(next: { [weak self] actions in + guard let self, !actions.options.isEmpty else { + return + } + self.presentBanMessageOptions( + accountPeerId: self.context.account.peerId, + author: peer._asPeer(), + messageIds: Set([message.id]), + options: actions.options, + reaction: true + ) + }) + }) } ))) } else { @@ -297,7 +325,9 @@ extension ChatControllerImpl { let presentationContext = self.controllerInteraction?.presentationContext let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) - if !packReferences.isEmpty && !premiumConfiguration.isPremiumDisabled { + if "".isEmpty { + items.tip = .deleteReaction + } else if !packReferences.isEmpty && !premiumConfiguration.isPremiumDisabled { items.tip = .animatedEmoji(text: nil, arguments: nil, file: nil, action: nil) if packReferences.count > 1 { diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenMessageShareMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenMessageShareMenu.swift index ea565b6fe6..992b1807ae 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenMessageShareMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenMessageShareMenu.swift @@ -92,6 +92,59 @@ func chatShareToSavedMessagesAdditionalView(_ chatController: ChatControllerImpl } extension ChatControllerImpl { +// func openMessageShareMenu(id: EngineMessage.Id) { +// guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first else { +// return +// } +// +// let chatPresentationInterfaceState = self.presentationInterfaceState +// var warnAboutPrivate = false +// var canShareToStory = false +// if case .peer = chatPresentationInterfaceState.chatLocation, let channel = message.peers[message.id.peerId] as? TelegramChannel { +// if case .broadcast = channel.info { +// canShareToStory = true +// if let message = messages.first, message.media.contains(where: { media in +// if media is TelegramMediaContact || media is TelegramMediaPoll || media is TelegramMediaTodo { +// return true +// } else if let file = media as? TelegramMediaFile, file.isSticker || file.isAnimatedSticker || file.isVideoSticker { +// return true +// } else { +// return false +// } +// }) { +// canShareToStory = false +// } +// if message.text.containsOnlyEmoji { +// canShareToStory = false +// } +// } +// if channel.addressName == nil { +// warnAboutPrivate = true +// } +// } +// +// let _ = warnAboutPrivate +// +//// let shareScreen = self.context.sharedContext.makeShareController( +//// context: self.context, +//// subject: .messages(messages), +//// forceExternal: false, +//// shareStory: canShareToStory ? { [weak self] in +//// guard let self else { +//// return +//// } +//// Queue.mainQueue().after(0.15) { +//// let controller = self.context.sharedContext.makeStorySharingScreen(context: self.context, subject: .messages(messages), parentController: self) +//// self.push(controller) +//// } +//// } : nil, +//// enqueued: nil, +//// actionCompleted: nil +//// ) +// self.chatDisplayNode.dismissInput() +// self.push(shareScreen) +// } + func openMessageShareMenu(id: EngineMessage.Id) { guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first else { return diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 8248671fb0..2e7ff6b0c8 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -2189,6 +2189,30 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState c?.dismiss(completion: { controllerInteraction.openPeer(peer, .default, MessageReference(message), hasReaction ? .reaction : .default) }) + }, + deleteReaction: { [weak c] peer, _ in + c?.dismiss(completion: { + guard let chatController = interfaceInteraction.chatController() as? ChatControllerImpl, chatController.chatLocation.peerId?.namespace == Namespaces.Peer.CloudChannel else { + return + } + let _ = (context.sharedContext.chatAvailableMessageActions( + engine: context.engine, + accountPeerId: context.account.peerId, + messageIds: Set([message.id]), + keepUpdated: false + ) + |> deliverOnMainQueue).startStandalone(next: { actions in + guard !actions.options.isEmpty else { + return + } + chatController.presentBanMessageOptions( + accountPeerId: context.account.peerId, + author: peer._asPeer(), + messageIds: Set([message.id]), + options: actions.options + ) + }) + }) } )), tip: tip))) } else { diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index 0550abb689..4d9447f65b 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -256,11 +256,14 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { } } + let fileReference: FileMediaReference = .message(message: MessageReference(params.message), media: file) let subject: BrowserScreen.Subject - if file.mimeType == "application/pdf" { - subject = .pdfDocument(file: .message(message: MessageReference(params.message), media: file), canShare: canShare) + if file.mimeType.contains("markdown") { + subject = .markdownDocument(file: fileReference, canShare: canShare) + } else if file.mimeType.contains("pdf") { + subject = .pdfDocument(file: fileReference, canShare: canShare) } else { - subject = .document(file: .message(message: MessageReference(params.message), media: file), canShare: canShare) + subject = .document(file: fileReference, canShare: canShare) } let controller = BrowserScreen(context: params.context, subject: subject) controller.openDocument = { [weak controller] file, canShare in diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 36620abb6e..0f68da6005 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -696,7 +696,7 @@ func openResolvedUrlImpl( present(shareController, nil) context.sharedContext.applicationBindings.dismissNativeController() } else { - let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled], selectForumThreads: true)) + let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled], hasFilters: true, selectForumThreads: true)) controller.peerSelected = { peer, threadId in continueWithPeer(peer.id, threadId) } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 9e0c754208..4e98f7899b 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -109,7 +109,7 @@ import EntityKeyboard private final class AccountUserInterfaceInUseContext { let subscribers = Bag<(Bool) -> Void>() let tokens = Bag() - + var isEmpty: Bool { return self.tokens.isEmpty && self.subscribers.isEmpty } @@ -295,7 +295,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { init(mainWindow: Window1?, sharedContainerPath: String, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager, appLockContext: AppLockContext, notificationController: NotificationContainerController?, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, hasInAppPurchases: Bool, rootPath: String, legacyBasePath: String?, apsNotificationToken: Signal, voipNotificationToken: Signal, firebaseSecretStream: Signal<[String: String], NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?, Bool) -> Void, displayUpgradeProgress: @escaping (Float?) -> Void = { _ in }, appDelegate: AppDelegate?, testingEnvironment: Bool = false) { assert(Queue.mainQueue().isCurrent()) - + precondition(!testHasInstance) testHasInstance = true diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index 35cd855bfb..29234377d7 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -83,6 +83,50 @@ public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [M private let syntaxHighlighter = Syntaxer() +private func isValidMessageSyntaxHighlightRange(_ range: Range, expectedLength: Int) -> Bool { + return range.lowerBound >= 0 && range.upperBound <= expectedLength && range.lowerBound < range.upperBound +} + +private func validatedCachedMessageSyntaxHighlight(_ highlight: MessageSyntaxHighlight, expectedLength: Int, language: String) -> MessageSyntaxHighlight? { + for entity in highlight.entities { + if !isValidMessageSyntaxHighlightRange(entity.range, expectedLength: expectedLength) { + return nil + } + } + return highlight +} + +private func generateMessageSyntaxHighlight(spec: CachedMessageSyntaxHighlight.Spec, theme: SyntaxterTheme) -> MessageSyntaxHighlight { + let expectedLength = (spec.text as NSString).length + guard let syntaxHighlighter else { + return MessageSyntaxHighlight(entities: []) + } + guard let highlightedString = syntaxHighlighter.syntax(spec.text, language: spec.language, theme: theme) else { + return MessageSyntaxHighlight(entities: []) + } + guard highlightedString.length == expectedLength else { + return MessageSyntaxHighlight(entities: []) + } + + var entities: [MessageSyntaxHighlight.Entity] = [] + var hasInvalidRange = false + highlightedString.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: highlightedString.length), using: { value, subRange, stop in + let range = subRange.lowerBound ..< subRange.upperBound + if !isValidMessageSyntaxHighlightRange(range, expectedLength: expectedLength) { + hasInvalidRange = true + stop.pointee = true + return + } + if let value = value as? UIColor, value != .black { + entities.append(MessageSyntaxHighlight.Entity(color: Int32(bitPattern: value.rgb), range: range)) + } + }) + if hasInvalidRange { + return MessageSyntaxHighlight(entities: []) + } + return MessageSyntaxHighlight(entities: entities) +} + public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], strings: PresentationStrings? = nil, dateTimeFormat: PresentationDateTimeFormat? = nil, baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, codeBlockTitleColor: UIColor? = nil, codeBlockAccentColor: UIColor? = nil, codeBlockBackgroundColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil, paragraphAlignment: NSTextAlignment? = nil) -> NSAttributedString { let baseQuoteTintColor = baseQuoteTintColor ?? baseColor @@ -399,8 +443,10 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti let codeText = (string.string as NSString).substring(with: range) if let cachedMessageSyntaxHighlight, let entry = cachedMessageSyntaxHighlight.values[CachedMessageSyntaxHighlight.Spec(language: language, text: codeText)] { - for entity in entry.entities { - string.addAttribute(.foregroundColor, value: UIColor(rgb: UInt32(bitPattern: entity.color)), range: NSRange(location: range.location + entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound)) + if let validatedEntry = validatedCachedMessageSyntaxHighlight(entry, expectedLength: range.length, language: language) { + for entity in validatedEntry.entities { + string.addAttribute(.foregroundColor, value: UIColor(rgb: UInt32(bitPattern: entity.color)), range: NSRange(location: range.location + entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound)) + } } } }) @@ -588,8 +634,18 @@ public func extractMessageSyntaxHighlightSpecs(text: String, entities: [MessageT private let internalFixedCodeFont = Font.regular(17.0) public func asyncUpdateMessageSyntaxHighlight(engine: TelegramEngine, messageId: EngineMessage.Id, current: CachedMessageSyntaxHighlight?, specs: [CachedMessageSyntaxHighlight.Spec]) -> Signal { - if let current, !specs.contains(where: { current.values[$0] == nil }) { - return .complete() + if let current { + var hasMissingOrInvalidSpec = false + for spec in specs { + let expectedLength = (spec.text as NSString).length + guard let value = current.values[spec], validatedCachedMessageSyntaxHighlight(value, expectedLength: expectedLength, language: spec.language) != nil else { + hasMissingOrInvalidSpec = true + break + } + } + if !hasMissingOrInvalidSpec { + return .complete() + } } return Signal { subscriber in @@ -598,22 +654,11 @@ public func asyncUpdateMessageSyntaxHighlight(engine: TelegramEngine, messageId: let theme = SyntaxterTheme(dark: false, textColor: .black, textFont: internalFixedCodeFont, italicFont: internalFixedCodeFont, mediumFont: internalFixedCodeFont) for spec in specs { + let expectedLength = (spec.text as NSString).length if let value = current?.values[spec] { - updated[spec] = value - } else { - var entities: [MessageSyntaxHighlight.Entity] = [] - - if let syntaxHighlighter { - if let highlightedString = syntaxHighlighter.syntax(spec.text, language: spec.language, theme: theme) { - highlightedString.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: highlightedString.length), using: { value, subRange, _ in - if let value = value as? UIColor, value != .black { - entities.append(MessageSyntaxHighlight.Entity(color: Int32(bitPattern: value.rgb), range: subRange.lowerBound ..< subRange.upperBound)) - } - }) - } - } - - updated[spec] = MessageSyntaxHighlight(entities: entities) + updated[spec] = validatedCachedMessageSyntaxHighlight(value, expectedLength: expectedLength, language: spec.language) ?? MessageSyntaxHighlight(entities: []) + } else if let theme { + updated[spec] = generateMessageSyntaxHighlight(spec: spec, theme: theme) } } @@ -629,8 +674,18 @@ public func asyncUpdateMessageSyntaxHighlight(engine: TelegramEngine, messageId: } public func asyncStanaloneSyntaxHighlight(current: CachedMessageSyntaxHighlight?, specs: [CachedMessageSyntaxHighlight.Spec]) -> Signal { - if let current, !specs.contains(where: { current.values[$0] == nil }) { - return .single(current) + if let current { + var hasMissingOrInvalidSpec = false + for spec in specs { + let expectedLength = (spec.text as NSString).length + guard let value = current.values[spec], validatedCachedMessageSyntaxHighlight(value, expectedLength: expectedLength, language: spec.language) != nil else { + hasMissingOrInvalidSpec = true + break + } + } + if !hasMissingOrInvalidSpec { + return .single(current) + } } return Signal { subscriber in @@ -639,22 +694,11 @@ public func asyncStanaloneSyntaxHighlight(current: CachedMessageSyntaxHighlight? let theme = SyntaxterTheme(dark: false, textColor: .black, textFont: internalFixedCodeFont, italicFont: internalFixedCodeFont, mediumFont: internalFixedCodeFont) for spec in specs { + let expectedLength = (spec.text as NSString).length if let value = current?.values[spec] { - updated[spec] = value - } else { - var entities: [MessageSyntaxHighlight.Entity] = [] - - if let syntaxHighlighter { - if let highlightedString = syntaxHighlighter.syntax(spec.text, language: spec.language, theme: theme) { - highlightedString.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: highlightedString.length), using: { value, subRange, _ in - if let value = value as? UIColor, value != .black { - entities.append(MessageSyntaxHighlight.Entity(color: Int32(bitPattern: value.rgb), range: subRange.lowerBound ..< subRange.upperBound)) - } - }) - } - } - - updated[spec] = MessageSyntaxHighlight(entities: entities) + updated[spec] = validatedCachedMessageSyntaxHighlight(value, expectedLength: expectedLength, language: spec.language) ?? MessageSyntaxHighlight(entities: []) + } else if let theme { + updated[spec] = generateMessageSyntaxHighlight(spec: spec, theme: theme) } } From 11af61f32ea4889188d37be7b92414f012be2665 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 Apr 2026 23:34:39 +0200 Subject: [PATCH 2/8] Fix build --- submodules/TelegramUI/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 59680b35d0..6c0c03c702 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -526,7 +526,6 @@ swift_library( "//submodules/TelegramUI/Components/RankChatPreviewItem", "//submodules/TelegramUI/Components/TextProcessingScreen", "//submodules/TelegramUI/Components/CreateBotScreen", - "//submodules/TelegramUI/Components/ShareScreen", "//submodules/Utils/AutomationBridge", ] + select({ "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, From 1fe13a76306a662f47e4b0462b502ff5805b4818 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 Apr 2026 23:51:28 +0200 Subject: [PATCH 3/8] Fix build --- submodules/TelegramUI/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 6c0c03c702..764a33bcce 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -526,7 +526,6 @@ swift_library( "//submodules/TelegramUI/Components/RankChatPreviewItem", "//submodules/TelegramUI/Components/TextProcessingScreen", "//submodules/TelegramUI/Components/CreateBotScreen", - "//submodules/Utils/AutomationBridge", ] + select({ "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "//build-system:ios_sim_arm64": [], From 7d3a497db6ad97b23ec60d0168b847be5fc56300 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 23 Apr 2026 00:07:09 +0200 Subject: [PATCH 4/8] Fix build --- submodules/TelegramUI/Sources/AppDelegate.swift | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 5513e8fe1b..1c1631c776 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -45,7 +45,6 @@ import RecaptchaEnterprise import NavigationBarImpl import ContextUI import ContextControllerImpl -import AutomationBridge #if canImport(AppCenter) import AppCenter @@ -1688,14 +1687,7 @@ private func extractAccountManagerState(records: AccountRecordsView Date: Thu, 23 Apr 2026 01:26:13 +0200 Subject: [PATCH 5/8] Various fixes --- .../Sources/Node/ChatListItem.swift | 4 +++ .../Sources/LocationViewControllerNode.swift | 6 ++-- .../Sources/AvatarGalleryController.swift | 34 +++++++++++++++++++ .../Sources/ChatAvatarNavigationNode.swift | 17 +++++++++- .../Sources/ChatMessageDateHeader.swift | 4 +++ 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 91962df4e2..43de3828f5 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -1969,6 +1969,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { profilePhoto = maybePhoto isKnown = true } + if profilePhoto == nil, case let .known(maybePhoto) = cachedPeerData.fallbackPhoto { + profilePhoto = maybePhoto + isKnown = true + } } if isKnown { diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index b2907103ef..136adc1235 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -356,7 +356,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan super.init() - self.backgroundColor = .red // self.presentationData.theme.list.plainBackgroundColor + self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor if !self.isPreview { self.addSubnode(self.listNode) @@ -656,7 +656,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction, gotTravelTimes: !travelTimes.isEmpty && !previousHadTravelTimes, animated: animated) strongSelf.enqueueTransition(transition) - strongSelf.headerNode.updateState(mapMode: state.mapMode, trackingMode: state.trackingMode, displayingMapModeOptions: state.displayingMapModeOptions, displayingPlacesButton: false, proximityNotification: proximityNotification, animated: false) + strongSelf.headerNode.updateState(mapMode: state.mapMode, trackingMode: state.trackingMode, displayingMapModeOptions: state.displayingMapModeOptions, displayingPlacesButton: false, proximityNotification: proximityNotification, animated: true) if let proximityNotification = proximityNotification, !proximityNotification && !strongSelf.displayedProximityAlertTooltip { strongSelf.displayedProximityAlertTooltip = true @@ -813,7 +813,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan self.presentationData = presentationData self.presentationDataPromise.set(.single(presentationData)) - self.backgroundColor = .red //self.presentationData.theme.list.plainBackgroundColor + self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor self.listNode.backgroundColor = .clear // self.presentationData.theme.list.plainBackgroundColor self.headerNode.updatePresentationData(self.presentationData) } diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 62724c5bde..80b75bf3d0 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -20,6 +20,28 @@ public enum AvatarGalleryEntryId: Hashable { case resource(String) } +private func avatarGalleryEntryMatchesImage(_ entry: AvatarGalleryEntry, _ image: TelegramMediaImage) -> Bool { + guard + let entryRepresentation = largestImageRepresentation(entry.representations.map({ $0.representation })), + let imageRepresentation = largestImageRepresentation(image.representations) + else { + return false + } + guard let entryResource = entryRepresentation.resource as? CloudPeerPhotoSizeMediaResource, let imageResource = imageRepresentation.resource as? CloudPhotoSizeMediaResource else { + return false + } + return entryResource.photoId == imageResource.photoId +} + +private func avatarGalleryEntryWithVideoRepresentations(_ entry: AvatarGalleryEntry, videoRepresentations: [VideoRepresentationWithReference], immediateThumbnailData: Data?) -> AvatarGalleryEntry { + switch entry { + case let .topImage(representations, _, peer, indexData, _, category): + return .topImage(representations, videoRepresentations, peer, indexData, immediateThumbnailData, category) + default: + return entry + } +} + public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id) -> Signal { return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> mapToSignal { peer -> Signal<[AvatarGalleryEntry]?, NoError> in @@ -48,6 +70,12 @@ public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id } if case let .known(photo) = cachedData.fallbackPhoto { lastEntry = photo + if let photo, firstEntry.videoRepresentations.isEmpty, !photo.videoRepresentations.isEmpty, avatarGalleryEntryMatchesImage(firstEntry, photo), let peerReference = PeerReference(peer) { + let videoRepresentations = photo.videoRepresentations.map { + VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) + } + firstEntry = avatarGalleryEntryWithVideoRepresentations(firstEntry, videoRepresentations: videoRepresentations, immediateThumbnailData: firstEntry.immediateThumbnailData ?? photo.immediateThumbnailData) + } } } return fetchedAvatarGalleryEntries(engine: context.engine, account: context.account, peer: EnginePeer(peer), firstEntry: firstEntry, secondEntry: secondEntry, lastEntry: lastEntry) @@ -311,6 +339,12 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account let initialEntries = [firstEntry] if photos.isEmpty { result = initialEntries + if let lastEntry, let firstEntry = result.first, firstEntry.videoRepresentations.isEmpty, !lastEntry.videoRepresentations.isEmpty, avatarGalleryEntryMatchesImage(firstEntry, lastEntry), let peerReference = PeerReference(peer._asPeer()) { + let videoRepresentations = lastEntry.videoRepresentations.map { + VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) + } + result[0] = avatarGalleryEntryWithVideoRepresentations(firstEntry, videoRepresentations: videoRepresentations, immediateThumbnailData: firstEntry.immediateThumbnailData ?? lastEntry.immediateThumbnailData) + } } else if let peerReference = PeerReference(peer._asPeer()) { var index: Int32 = 0 diff --git a/submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode/Sources/ChatAvatarNavigationNode.swift b/submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode/Sources/ChatAvatarNavigationNode.swift index 62e8aceb8b..27b644ffa8 100644 --- a/submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode/Sources/ChatAvatarNavigationNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode/Sources/ChatAvatarNavigationNode.swift @@ -112,7 +112,18 @@ public final class ChatAvatarNavigationNode: ASDisplayNode { self.avatarNode.isHidden = true } - public func setPeer(context: AccountContext, theme: PresentationTheme, peer: EnginePeer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), storeUnrounded: Bool = false) { + public func setPeer( + context: AccountContext, + theme: PresentationTheme, + peer: EnginePeer?, + authorOfMessage: MessageReference? = nil, + overrideImage: AvatarNodeImageOverride? = nil, + emptyColor: UIColor? = nil, + clipStyle: AvatarNodeClipStyle = .round, + synchronousLoad: Bool = false, + displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), + storeUnrounded: Bool = false + ) { self.context = context if let statusComponentView = self.statusView.view { @@ -162,6 +173,10 @@ public final class ChatAvatarNavigationNode: ASDisplayNode { profilePhoto = maybePhoto isKnown = true } + if profilePhoto == nil, case let .known(maybePhoto) = cachedPeerData.fallbackPhoto { + profilePhoto = maybePhoto + isKnown = true + } } if isKnown { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageDateHeader.swift index 42b4a3638f..05c31d02ab 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageDateHeader.swift @@ -1102,6 +1102,10 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat profilePhoto = maybePhoto isKnown = true } + if profilePhoto == nil, case let .known(maybePhoto) = cachedPeerData.fallbackPhoto { + profilePhoto = maybePhoto + isKnown = true + } } if isKnown { From 32b2ede5aa16ff2062103e7bdb342afc78687f94 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 23 Apr 2026 01:48:48 +0200 Subject: [PATCH 6/8] Fix data image sharing --- .../ShareItems/Impl/Sources/TGItemProviderSignals.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/submodules/ShareItems/Impl/Sources/TGItemProviderSignals.m b/submodules/ShareItems/Impl/Sources/TGItemProviderSignals.m index 92aeb2c25e..7989e9583e 100644 --- a/submodules/ShareItems/Impl/Sources/TGItemProviderSignals.m +++ b/submodules/ShareItems/Impl/Sources/TGItemProviderSignals.m @@ -184,13 +184,13 @@ __unused static CGSize TGFitSize(CGSize size, CGSize maxSize) { if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) { [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:imageOptions completionHandler:^(id _Nullable item, NSError * _Null_unspecified error) { if (error != nil && ![(NSObject *)item respondsToSelector:@selector(CGImage)] && ![(NSObject *)item respondsToSelector:@selector(absoluteString)]) { - [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(UIImage *image, NSError *error) + [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(NSData *data, NSError *error) { if (error != nil) [subscriber putError:nil]; else { - [subscriber putNext:@{@"image": image}]; + [subscriber putNext:@{@"data": data}]; [subscriber putCompletion]; } }]; @@ -263,13 +263,13 @@ __unused static CGSize TGFitSize(CGSize size, CGSize maxSize) { } }]; } else { - [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(UIImage *image, NSError *error) + [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(NSData *data, NSError *error) { if (error != nil) [subscriber putError:nil]; else { - [subscriber putNext:@{@"image": image}]; + [subscriber putNext:@{@"data": data}]; [subscriber putCompletion]; } }]; From f41630083a21b4f5626eb34f6f99c47e3e44299f Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 24 Apr 2026 03:16:14 +0200 Subject: [PATCH 7/8] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 8 + .../Sources/ContactSelectionController.swift | 2 +- .../AuthorizationSequenceController.swift | 4 +- .../AuthorizationSequencePaymentScreen.swift | 2 +- submodules/BrowserUI/BUILD | 1 + .../Sources/BrowserInstantPageContent.swift | 100 ++++- .../BrowserUI/Sources/BrowserMarkdown.swift | 20 +- .../Sources/BrowserReadability.swift | 12 +- .../Sources/ChatListController.swift | 23 +- .../Sources/ChatListControllerNode.swift | 28 +- submodules/Emoji/Sources/EmojiUtils.swift | 26 ++ submodules/InstantPageUI/BUILD | 1 + .../Sources/InstantPageLayout.swift | 130 ++++++- .../Sources/InstantPageLayoutSpacings.swift | 6 +- .../Sources/InstantPageTheme.swift | 26 ++ .../TGAttachmentCarouselItemView.h | 2 +- .../LegacyComponents/TGCameraController.h | 2 +- .../TGMediaAssetsController.h | 2 +- .../TGMediaPickerController.h | 2 +- .../TGMediaPickerModernGalleryMixin.h | 2 +- .../LegacyComponents/TGPhotoVideoEditor.h | 2 +- .../TGVideoMessageCaptureController.h | 2 +- .../Sources/TGCameraController.m | 4 +- .../Sources/TGMediaAssetsController.m | 6 +- .../Sources/TGMediaPickerModernGalleryMixin.m | 4 +- .../Sources/TGPhotoVideoEditor.m | 4 +- .../Sources/TGVideoMessageCaptureController.m | 4 +- .../Sources/LegacyAttachmentMenu.swift | 10 +- .../Sources/LegacyMediaPickers.swift | 6 +- .../Sources/LegacyMediaPickerGallery.swift | 6 +- .../Sources/MediaPickerScreen.swift | 6 +- .../Sources/NotificationSoundSelection.swift | 2 +- ...tupTwoStepVerificationControllerNode.swift | 2 +- .../TwoFactorAuthDataInputScreen.swift | 4 +- .../Sources/ChannelAdminController.swift | 10 +- .../ChannelBannedMemberController.swift | 4 +- .../ChannelPermissionsController.swift | 6 + .../CreatePasswordController.swift | 2 +- .../TermsOfServiceController.swift | 2 +- submodules/TelegramApi/Sources/Api40.swift | 33 ++ .../Models/InstantPageBlock.fbs | 9 +- .../Sources/ApiUtils/InstantPage.swift | 2 +- .../SyncCore/SyncCore_InstantPage.swift | 52 ++- .../SyncCore_TelegramChatBannedRights.swift | 1 + .../Messages/DeleteMessages.swift | 38 ++ .../Messages/TelegramEngineMessages.swift | 8 + .../Sources/AdminUserActionsSheet.swift | 12 +- .../Sources/ChatMessageBubbleItemNode.swift | 6 +- .../Sources/ChatTextInputPanelNode.swift | 2 +- .../Sources/ChatParticipantRightsScreen.swift | 2 +- .../Sources/ChatScheduleTimeScreen.swift | 33 +- .../Sources/EmojiPagerContentComponent.swift | 57 ++- .../Sources/GiftViewScreen.swift | 2 +- .../LegacyCamera/Sources/LegacyCamera.swift | 6 +- .../LegacyInstantVideoController.swift | 6 +- .../NotificationPeerExceptionController.swift | 2 +- .../Sources/PeerInfoScreen.swift | 2 +- .../Sources/PeerInfoStoryPaneNode.swift | 2 +- .../Components/ShareExtensionContext/BUILD | 2 + .../Sources/ShareExtensionContext.swift | 14 + ...StoryItemSetContainerViewSendMessage.swift | 59 +-- .../Sources/VideoMessageCameraScreen.swift | 16 +- .../Sources/Chat/ChatControllerEditGif.swift | 6 +- .../Chat/ChatControllerLoadDisplayNode.swift | 5 +- .../Chat/ChatControllerMediaRecording.swift | 24 +- ...UpdateChatPresentationInterfaceState.swift | 4 +- .../TelegramUI/Sources/ChatController.swift | 44 ++- .../Sources/ChatControllerAdminBanUsers.swift | 33 +- .../ChatControllerForwardMessages.swift | 6 +- .../ChatControllerOpenAttachmentMenu.swift | 46 +-- .../ChatInterfaceInputContextPanels.swift | 34 +- .../Sources/ContactSelectionController.swift | 6 +- .../Sources/CreateChannelController.swift | 347 +++++++---------- .../Sources/CreateGroupController.swift | 353 ++++++++---------- .../Sources/CreatePeerAvatarSetup.swift | 216 +++++++++++ ...textResultsChatInputContextPanelNode.swift | 3 +- .../Sources/WebSearchController.swift | 10 +- 77 files changed, 1303 insertions(+), 685 deletions(-) create mode 100644 submodules/TelegramUI/Sources/CreatePeerAvatarSetup.swift diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 71e02d506c..73f827f844 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -16208,3 +16208,11 @@ Error: %8$@"; "Settings.Birthday.PrivacyHelpEveryone" = "Everyone can see your birthday. [Change >]()"; "Settings.Birthday.PrivacyHelpContacts" = "Only your contacts can see your birthday. [Change >]()"; "Settings.Birthday.PrivacyHelpNobody" = "Nobody can see your birthday. [Change >]()"; + +"GroupPermission.NoSendReactions" = "no reactions"; +"Channel.BanUser.PermissionSendReactions" = "Send Reactions"; + +"Chat.AdminAction.ToastReactionsDeletedTitleSingle" = "Reaction Deleted"; +"Chat.AdminAction.ToastReactionsDeletedTextSingle" = "Reaction Deleted."; +"Chat.AdminAction.ToastReactionsDeletedTextMultiple" = "Messages Deleted."; +"Chat.AdminAction.ToastMessagesAndReactionsDeletedText" = "Messages and reactions deleted."; diff --git a/submodules/AccountContext/Sources/ContactSelectionController.swift b/submodules/AccountContext/Sources/ContactSelectionController.swift index 54d5cb44ad..4b256510b1 100644 --- a/submodules/AccountContext/Sources/ContactSelectionController.swift +++ b/submodules/AccountContext/Sources/ContactSelectionController.swift @@ -9,7 +9,7 @@ public protocol ContactSelectionController: ViewController { var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?, ChatSendMessageActionSheetController.SendParameters?)?, NoError> { get } var displayProgress: Bool { get set } var dismissed: (() -> Void)? { get set } - var presentScheduleTimePicker: (@escaping (Int32, Int32?) -> Void) -> Void { get set } + var presentScheduleTimePicker: (@escaping (Int32, Int32?, Bool) -> Void) -> Void { get set } func dismissSearch() } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index e5fc76b8b4..313d21980a 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -997,7 +997,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth controller.reset = { [weak self, weak controller] in if let strongSelf = self, let strongController = controller { strongController.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: suggestReset ? strongSelf.presentationData.strings.TwoStepAuth_RecoveryFailed : strongSelf.presentationData.strings.TwoStepAuth_RecoveryUnavailable, actions: [ - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.Login_ResetAccountProtected_Reset, action: { if let strongSelf = self, let strongController = controller { strongController.inProgress = true @@ -1084,7 +1084,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth controller.reset = { [weak self, weak controller] in if let strongSelf = self, let strongController = controller { strongController.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.TwoStepAuth_ResetAccountConfirmation, actions: [ - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.Login_ResetAccountProtected_Reset, action: { if let strongSelf = self, let strongController = controller { strongController.inProgress = true diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 20f70b12ce..07fe4c61f9 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -168,7 +168,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { title: nil, text: errorText, actions: [ - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}), + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in guard let self else { return diff --git a/submodules/BrowserUI/BUILD b/submodules/BrowserUI/BUILD index 74cd9f60b2..8b9315a112 100644 --- a/submodules/BrowserUI/BUILD +++ b/submodules/BrowserUI/BUILD @@ -31,6 +31,7 @@ swift_library( "//submodules/TelegramUI/Components/MinimizedContainer", "//submodules/Pasteboard", "//submodules/SaveToCameraRoll", + "//submodules/TextFormat:TextFormat", "//submodules/TelegramUI/Components/NavigationStackComponent", "//submodules/LocationUI", "//submodules/OpenInExternalAppUI", diff --git a/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift b/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift index 4f9c55b877..55ccbbbf00 100644 --- a/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift +++ b/submodules/BrowserUI/Sources/BrowserInstantPageContent.swift @@ -20,6 +20,7 @@ import SafariServices import LocationUI import OpenInExternalAppUI import GalleryUI +import TextFormat final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDelegate { private let context: AccountContext @@ -67,6 +68,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg var currentDetailsItems: [InstantPageDetailsItem] = [] private var resolvedExternalMediaDimensions: [MediaId: PixelDimensions] = [:] private var pendingResolvedExternalMediaDimensions = Set() + private var codeHighlight: CachedMessageSyntaxHighlight? + private var codeHighlightState: (specs: [CachedMessageSyntaxHighlight.Spec], disposable: Disposable)? var currentAccessibilityAreas: [AccessibilityAreaNode] = [] @@ -90,6 +93,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg private let resolveUrlDisposable = MetaDisposable() private let updateLayoutDisposable = MetaDisposable() private let updateExternalMediaDimensionsDisposable = MetaDisposable() + private let updateCodeHighlightDisposable = MetaDisposable() private let loadProgress = ValuePromise(1.0, ignoreRepeated: true) private let readingProgress = ValuePromise(0.0, ignoreRepeated: true) @@ -190,6 +194,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg self.updateWebPage(result, anchor: self.initialAnchor) }) } + + self.updateCodeHighlight() } deinit { @@ -199,6 +205,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg self.resolveUrlDisposable.dispose() self.updateLayoutDisposable.dispose() self.updateExternalMediaDimensionsDisposable.dispose() + self.updateCodeHighlightDisposable.dispose() } required init?(coder: NSCoder) { @@ -325,6 +332,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg } } self.currentLayout = nil + self.updateCodeHighlight() self.updatePageLayout() self.scrollNode.frame = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) @@ -490,7 +498,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg return } - let currentLayout = instantPageLayoutForWebPage(webPage, instantPage: instantPage, userLocation: self.sourceLocation.userLocation, boundingWidth: size.width, safeInset: insets.left, strings: self.presentationData.strings, theme: self.theme, dateTimeFormat: self.presentationData.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights) + let currentLayout = instantPageLayoutForWebPage(webPage, instantPage: instantPage, userLocation: self.sourceLocation.userLocation, boundingWidth: size.width, safeInset: insets.left, strings: self.presentationData.strings, theme: self.theme, dateTimeFormat: self.presentationData.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights, cachedMessageSyntaxHighlight: self.codeHighlight) let currentLayoutTiles = instantPageTilesFromLayout(currentLayout, boundingWidth: size.width) @@ -551,6 +559,96 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg self.scrollNode.view.contentSize = currentLayout.contentSize self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: currentLayout.contentSize.height), size: CGSize(width: size.width, height: 2000.0)) } + + private func updateCodeHighlight() { + guard let instantPage = self.webPage?.instantPage else { + self.codeHighlight = nil + self.codeHighlightState = nil + self.updateCodeHighlightDisposable.set(nil) + return + } + + let specs = syntaxHighlightSpecs(for: instantPage.blocks) + if let currentState = self.codeHighlightState, currentState.specs == specs { + return + } + + if specs.isEmpty { + let hadHighlight = self.codeHighlight != nil + self.codeHighlight = nil + self.codeHighlightState = nil + self.updateCodeHighlightDisposable.set(nil) + if hadHighlight { + self.updatePageLayout() + self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds) + } + return + } + + let disposable = MetaDisposable() + self.codeHighlightState = (specs, disposable) + self.updateCodeHighlightDisposable.set(disposable) + disposable.set((asyncStanaloneSyntaxHighlight(current: self.codeHighlight, specs: specs) + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let self else { + return + } + if self.codeHighlight != result { + self.codeHighlight = result + self.updatePageLayout() + self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds) + } + })) + } + + private func syntaxHighlightSpecs(for blocks: [InstantPageBlock]) -> [CachedMessageSyntaxHighlight.Spec] { + var specs: [CachedMessageSyntaxHighlight.Spec] = [] + var seen = Set() + + func collect(blocks: [InstantPageBlock]) { + for block in blocks { + switch block { + case let .preformatted(text, language): + guard let language = normalizedCodeBlockLanguage(language), !text.plainText.isEmpty else { + continue + } + let spec = CachedMessageSyntaxHighlight.Spec(language: language, text: text.plainText) + if seen.insert(spec).inserted { + specs.append(spec) + } + case let .cover(block): + collect(blocks: [block]) + case let .postEmbed(_, _, _, _, _, blocks, _): + collect(blocks: blocks) + case let .collage(items, _): + collect(blocks: items) + case let .slideshow(items, _): + collect(blocks: items) + case let .details(_, blocks, _): + collect(blocks: blocks) + case let .list(items, _): + for item in items { + if case let .blocks(blocks, _) = item { + collect(blocks: blocks) + } + } + default: + break + } + } + } + + collect(blocks: blocks) + return specs + } + + private func normalizedCodeBlockLanguage(_ language: String?) -> String? { + guard let language else { + return nil + } + let normalized = language.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() + return normalized.isEmpty ? nil : normalized + } func updateVisibleItems(visibleBounds: CGRect, animated: Bool = false) { var visibleTileIndices = Set() diff --git a/submodules/BrowserUI/Sources/BrowserMarkdown.swift b/submodules/BrowserUI/Sources/BrowserMarkdown.swift index 3f09ec5cd4..debef1e807 100644 --- a/submodules/BrowserUI/Sources/BrowserMarkdown.swift +++ b/submodules/BrowserUI/Sources/BrowserMarkdown.swift @@ -330,7 +330,7 @@ private func markdownBlocks(from node: MarkdownIntentNode, context: MarkdownConv } else if level == 2 { return [.header(text)] } else { - return [.subheader(text)] + return [.heading(text: text, level: Int32(max(3, min(level, 6))))] } case .paragraph: let inlineContent = markdownInlineContent(from: node.attributedText, context: context) @@ -349,12 +349,12 @@ private func markdownBlocks(from node: MarkdownIntentNode, context: MarkdownConv return [] } return [.paragraph(text)] - case .codeBlock: + case let .codeBlock(languageHint): let text = markdownRichText(from: markdownTrimTrailingCodeBlockNewline(node.attributedText), context: context) guard markdownHasDisplayableContent(text) else { return [] } - return [.preformatted(text)] + return [.preformatted(text: text, language: markdownNormalizedCodeBlockLanguage(languageHint))] case .thematicBreak: return [.divider] case .blockQuote: @@ -897,9 +897,11 @@ private func markdownPlainText(from block: InstantPageBlock) -> String { return text.plainText case let .subheader(text): return text.plainText + case let .heading(text, _): + return text.plainText case let .paragraph(text): return text.plainText - case let .preformatted(text): + case let .preformatted(text, _): return text.plainText case let .footer(text): return text.plainText @@ -940,6 +942,14 @@ private func markdownTitle(from blocks: [InstantPageBlock], file: FileMediaRefer return fileURL.lastPathComponent } +private func markdownNormalizedCodeBlockLanguage(_ language: String?) -> String? { + guard let language else { + return nil + } + let normalized = language.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() + return normalized.isEmpty ? nil : normalized +} + private func markdownFirstParagraphText(from blocks: [InstantPageBlock]) -> String? { for block in blocks { switch block { @@ -1007,6 +1017,8 @@ private func markdownHeadingText(from block: InstantPageBlock) -> String? { return text.plainText case let .subheader(text): return text.plainText + case let .heading(text, _): + return text.plainText default: return nil } diff --git a/submodules/BrowserUI/Sources/BrowserReadability.swift b/submodules/BrowserUI/Sources/BrowserReadability.swift index 4f734d98e4..3f5a45c894 100644 --- a/submodules/BrowserUI/Sources/BrowserReadability.swift +++ b/submodules/BrowserUI/Sources/BrowserReadability.swift @@ -747,10 +747,16 @@ private func parsePageBlocks(_ input: [Any], _ url: String, _ media: inout [Medi result.append(.paragraph(trim(parseRichText(item, &media)))) case "h1", "h2": result.append(.header(trim(parseRichText(item, &media)))) - case "h3", "h4", "h5", "h6": - result.append(.subheader(trim(parseRichText(item, &media)))) + case "h3": + result.append(.heading(text: trim(parseRichText(item, &media)), level: 3)) + case "h4": + result.append(.heading(text: trim(parseRichText(item, &media)), level: 4)) + case "h5": + result.append(.heading(text: trim(parseRichText(item, &media)), level: 5)) + case "h6": + result.append(.heading(text: trim(parseRichText(item, &media)), level: 6)) case "pre": - result.append(.preformatted(.fixed(trim(parseRichText(item, &media))))) + result.append(.preformatted(text: .fixed(trim(parseRichText(item, &media))), language: nil)) case "blockquote": result.append(.blockQuote(text: .italic(trim(parseRichText(item, &media))), caption: .empty)) case "img": diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 6e2cbd0c81..dcd30d5bb8 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -163,6 +163,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return false } } + + private var foldersCount: Int32 { + guard let tabContainerData = self.tabContainerData else { + return 0 + } + return Int32(tabContainerData.0.count(where: { entry in + if case .filter = entry { + return true + } else { + return false + } + })) + } private var hasDownloads: Bool = false private var activeDownloadsDisposable: Disposable? @@ -1015,7 +1028,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if isDisabled { let context = self.context var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .folders, count: Int32(self.tabContainerData?.0.count ?? 0), action: { + let controller = PremiumLimitScreen(context: context, subject: .folders, count: self.foldersCount, action: { let controller = PremiumIntroScreen(context: context, source: .folders) replaceImpl?(controller) return true @@ -1059,7 +1072,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if isDisabled { let context = self.context var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .folders, count: Int32(self.tabContainerData?.0.count ?? 0), action: { + let controller = PremiumLimitScreen(context: context, subject: .folders, count: self.foldersCount, action: { let controller = PremiumIntroScreen(context: context, source: .folders) replaceImpl?(controller) return true @@ -2377,7 +2390,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } let context = strongSelf.context var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .folders, count: Int32(strongSelf.tabContainerData?.0.count ?? 0), action: { + let controller = PremiumLimitScreen(context: context, subject: .folders, count: strongSelf.foldersCount, action: { let controller = PremiumIntroScreen(context: context, source: .folders) replaceImpl?(controller) return true @@ -4563,7 +4576,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: { confirmDeleteFolder() }), - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { }) ]), in: .window(.root)) } else { @@ -6251,7 +6264,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if isDisabled { let context = strongSelf.context var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .folders, count: Int32(strongSelf.tabContainerData?.0.count ?? 0), action: { + let controller = PremiumLimitScreen(context: context, subject: .folders, count: strongSelf.foldersCount, action: { let controller = PremiumIntroScreen(context: context, source: .folders) replaceImpl?(controller) return true diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index a036e41e04..826aa80f86 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -1504,6 +1504,24 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate { if self.controller?.tabContainerData != nil || !panels.isEmpty { var tabs: AnyComponent? if let tabContainerData = self.controller?.tabContainerData, tabContainerData.0.count > 1 { + let folderFilterIndex: (ChatListFilterTabEntryId, [ChatListFilterTabEntry]) -> Int? = { id, entries in + var index = 0 + for entry in entries { + switch entry { + case .all: + if entry.id == id { + return nil + } + case .filter: + if entry.id == id { + return index + } + index += 1 + } + } + return nil + } + let selectedTab: HorizontalTabsComponent.Tab.Id switch self.effectiveContainerNode.currentItemFilter { case .all: @@ -1553,10 +1571,9 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate { var isDisabled = false if let filtersLimit = tabContainerData.2 { - guard let folderIndex = tabContainerData.0.firstIndex(where: { $0.id == mappedId }) else { - return + if let folderIndex = folderFilterIndex(mappedId, tabContainerData.0) { + isDisabled = !isPremium && folderIndex >= filtersLimit } - isDisabled = !isPremium && folderIndex >= filtersLimit } if isDisabled { @@ -1599,10 +1616,9 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate { var isDisabled = false if let filtersLimit = tabContainerData.2 { - guard let folderIndex = tabContainerData.0.firstIndex(where: { $0.id == entry.id }) else { - return + if let folderIndex = folderFilterIndex(entry.id, tabContainerData.0) { + isDisabled = !isPremium && folderIndex >= filtersLimit } - isDisabled = !isPremium && folderIndex >= filtersLimit } self.controller?.tabContextGesture(id: mappedId, sourceNode: nil, sourceView: sourceView, gesture: gesture, keepInPlace: false, isDisabled: isDisabled) diff --git a/submodules/Emoji/Sources/EmojiUtils.swift b/submodules/Emoji/Sources/EmojiUtils.swift index 4b5033e7b8..b31549fcd6 100644 --- a/submodules/Emoji/Sources/EmojiUtils.swift +++ b/submodules/Emoji/Sources/EmojiUtils.swift @@ -57,6 +57,18 @@ public extension UnicodeScalar { private final class FrameworkClass: NSObject { } +private let allowedEmojiLikeSymbols: Set = [ + "\u{2640}", + "\u{2640}\u{FE0E}", + "\u{2640}\u{FE0F}", + "\u{2642}", + "\u{2642}\u{FE0E}", + "\u{2642}\u{FE0F}", + "\u{26A7}", + "\u{26A7}\u{FE0E}", + "\u{26A7}\u{FE0F}" +] + public extension String { func trimmingTrailingSpaces() -> String { var t = self @@ -74,6 +86,20 @@ public extension String { return self.contains { $0.isEmoji } } + var containsGraphicEmoji: Bool { + var containsEmoji = false + self.enumerateSubstrings(in: self.startIndex ..< self.endIndex, options: .byComposedCharacterSequences) { substring, _, _, stop in + guard let substring else { + return + } + if substring.containsEmoji && !allowedEmojiLikeSymbols.contains(substring) { + containsEmoji = true + stop = true + } + } + return containsEmoji + } + var containsOnlyEmoji: Bool { return !self.isEmpty && !self.contains { !$0.isEmoji } } diff --git a/submodules/InstantPageUI/BUILD b/submodules/InstantPageUI/BUILD index 52f8e2ec5f..34ee3765ae 100644 --- a/submodules/InstantPageUI/BUILD +++ b/submodules/InstantPageUI/BUILD @@ -17,6 +17,7 @@ swift_library( "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/TextFormat:TextFormat", "//submodules/GalleryUI:GalleryUI", "//submodules/MusicAlbumArtResources:MusicAlbumArtResources", "//submodules/LiveLocationPositionNode:LiveLocationPositionNode", diff --git a/submodules/InstantPageUI/Sources/InstantPageLayout.swift b/submodules/InstantPageUI/Sources/InstantPageLayout.swift index a19a069f7f..2f07bcd4dc 100644 --- a/submodules/InstantPageUI/Sources/InstantPageLayout.swift +++ b/submodules/InstantPageUI/Sources/InstantPageLayout.swift @@ -6,6 +6,7 @@ import TelegramPresentationData import TelegramUIPreferences import TelegramStringFormatting import MosaicLayout +import TextFormat public final class InstantPageLayout { public let origin: CGPoint @@ -28,8 +29,7 @@ public final class InstantPageLayout { } } -private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantPageTheme, category: InstantPageTextCategoryType, link: Bool) { - let attributes = theme.textCategories.attributes(type: category, link: link) +private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantPageTheme, attributes: InstantPageTextAttributes) { stack.push(.textColor(attributes.color)) stack.push(.markerColor(theme.markerColor)) stack.push(.linkColor(theme.linkColor)) @@ -47,7 +47,91 @@ private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantP } } -public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: MediaResourceUserLocation, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToSize: CGSize?, media: [EngineMedia.Id: EngineMedia], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, detailsIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:], excludeCaptions: Bool) -> InstantPageLayout { +private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantPageTheme, category: InstantPageTextCategoryType, link: Bool) { + setupStyleStack(stack, theme: theme, attributes: theme.textCategories.attributes(type: category, link: link)) +} + +private func instantPageFont(style: InstantPageTextAttributes, bold: Bool = false, italic: Bool = false, fixed: Bool = false) -> UIFont { + let size = style.font.size + if fixed { + if bold && italic { + return UIFont(name: "Menlo-BoldItalic", size: size) ?? Font.semiboldItalic(size) + } else if bold { + return UIFont(name: "Menlo-Bold", size: size) ?? Font.bold(size) + } else if italic { + return UIFont(name: "Menlo-Italic", size: size) ?? Font.italic(size) + } else { + return UIFont(name: "Menlo", size: size) ?? Font.regular(size) + } + } + switch style.font.style { + case .serif: + if bold && italic { + return UIFont(name: "Georgia-BoldItalic", size: size) ?? Font.semiboldItalic(size) + } else if bold { + return UIFont(name: "Georgia-Bold", size: size) ?? Font.bold(size) + } else if italic { + return UIFont(name: "Georgia-Italic", size: size) ?? Font.italic(size) + } else { + return UIFont(name: "Georgia", size: size) ?? Font.regular(size) + } + case .sans: + if bold && italic { + return Font.semiboldItalic(size) + } else if bold { + return Font.bold(size) + } else if italic { + return Font.italic(size) + } else { + return Font.regular(size) + } + } +} + +private func attributedStringForPreformattedText(_ text: RichText, language: String?, theme: InstantPageTheme, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight?) -> NSAttributedString { + let paragraphAttributes = theme.textCategories.attributes(type: .paragraph, link: false) + let textValue = text.plainText + guard !textValue.isEmpty else { + return NSAttributedString( + string: "", + attributes: [ + .font: instantPageFont(style: paragraphAttributes, fixed: true), + .foregroundColor: paragraphAttributes.color, + NSAttributedString.Key(rawValue: InstantPageLineSpacingFactorAttribute): paragraphAttributes.font.lineSpacingFactor as NSNumber + ] + ) + } + + let attributedString = stringWithAppliedEntities( + textValue, + entities: [ + MessageTextEntity(range: 0 ..< (textValue as NSString).length, type: .Pre(language: language)) + ], + baseColor: paragraphAttributes.color, + linkColor: theme.linkColor, + codeBlockTitleColor: paragraphAttributes.color, + codeBlockAccentColor: paragraphAttributes.color, + codeBlockBackgroundColor: theme.codeBlockBackgroundColor, + baseFont: instantPageFont(style: paragraphAttributes), + linkFont: instantPageFont(style: paragraphAttributes), + boldFont: instantPageFont(style: paragraphAttributes, bold: true), + italicFont: instantPageFont(style: paragraphAttributes, italic: true), + boldItalicFont: instantPageFont(style: paragraphAttributes, bold: true, italic: true), + fixedFont: instantPageFont(style: paragraphAttributes, fixed: true), + blockQuoteFont: instantPageFont(style: paragraphAttributes), + underlineLinks: false, + message: nil, + cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight + ).mutableCopy() as! NSMutableAttributedString + attributedString.addAttribute( + NSAttributedString.Key(rawValue: InstantPageLineSpacingFactorAttribute), + value: paragraphAttributes.font.lineSpacingFactor as NSNumber, + range: NSRange(location: 0, length: attributedString.length) + ) + return attributedString +} + +public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: MediaResourceUserLocation, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToSize: CGSize?, media: [EngineMedia.Id: EngineMedia], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, detailsIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:], cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil, excludeCaptions: Bool) -> InstantPageLayout { let layoutCaption: (InstantPageCaption, CGSize) -> ([InstantPageItem], CGSize) = { caption, contentSize in var items: [InstantPageItem] = [] @@ -100,7 +184,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: switch block { case let .cover(block): - return layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToSize: fillToSize, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false) + return layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToSize: fillToSize, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: false) case let .title(text): let styleStack = InstantPageTextStyleStack() setupStyleStack(styleStack, theme: theme, category: .header, link: false) @@ -168,16 +252,34 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: setupStyleStack(styleStack, theme: theme, category: .subheader, link: false) let (_, items, contentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0, offset: CGPoint(x: horizontalInset, y: 0.0), media: media, webpage: webpage) return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items) + case let .heading(text, level): + let styleStack = InstantPageTextStyleStack() + setupStyleStack(styleStack, theme: theme, attributes: theme.headingTextAttributes(level: level, link: false)) + let (_, items, contentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0, offset: CGPoint(x: horizontalInset, y: 0.0), media: media, webpage: webpage) + return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items) case let .paragraph(text): let styleStack = InstantPageTextStyleStack() setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false) let (_, items, contentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0, horizontalInset: horizontalInset, offset: CGPoint(x: horizontalInset, y: 0.0), media: media, webpage: webpage) return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items) - case let .preformatted(text): - let styleStack = InstantPageTextStyleStack() - setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false) + case let .preformatted(text, language): let backgroundInset: CGFloat = 14.0 - let (_, items, contentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0 - backgroundInset * 2.0, offset: CGPoint(x: 17.0, y: backgroundInset), media: media, webpage: webpage, opaqueBackground: true) + let attributedString: NSAttributedString + if let language, !language.isEmpty { + attributedString = attributedStringForPreformattedText(text, language: language, theme: theme, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight) + } else { + let styleStack = InstantPageTextStyleStack() + setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false) + attributedString = attributedStringForRichText(text, styleStack: styleStack) + } + let (_, items, contentSize) = layoutTextItemWithString( + attributedString, + boundingWidth: boundingWidth - horizontalInset * 2.0 - backgroundInset * 2.0, + offset: CGPoint(x: 17.0, y: backgroundInset), + media: media, + webpage: webpage, + opaqueBackground: true + ) let backgroundItem = InstantPageShapeItem(frame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: contentSize.height + backgroundInset * 2.0)), shapeFrame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: contentSize.height + backgroundInset * 2.0)), shape: .rect, color: theme.codeBlockBackgroundColor) var allItems: [InstantPageItem] = [backgroundItem] allItems.append(contentsOf: items) @@ -274,7 +376,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: var previousBlock: InstantPageBlock? var originY: CGFloat = contentSize.height for subBlock in blocks { - let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false) + let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: false) let spacing: CGFloat = previousBlock != nil && subLayout.contentSize.height > 0.0 ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0 let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing)) @@ -476,7 +578,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: var i = 0 for subItem in innerItems { let frame = mosaicLayout[i].0 - let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subItem, boundingWidth: frame.width, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: frame.size, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: true) + let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subItem, boundingWidth: frame.width, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: frame.size, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: true) items.append(contentsOf: subLayout.flattenedItemsWithOrigin(frame.origin)) i += 1 } @@ -550,7 +652,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: var previousBlock: InstantPageBlock? for subBlock in blocks { - let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false) + let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: false) let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock) let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + lineInset, y: contentSize.height + spacing)) @@ -733,7 +835,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: var previousBlock: InstantPageBlock? for subBlock in blocks { - let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: false, previousItems: subitems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &subDetailsIndex, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false) + let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: false, previousItems: subitems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &subDetailsIndex, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: false) let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock) let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing)) @@ -842,7 +944,7 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: } } -public func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, instantPage: InstantPage?, userLocation: MediaResourceUserLocation, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:]) -> InstantPageLayout { +public func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, instantPage: InstantPage?, userLocation: MediaResourceUserLocation, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:], cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil) -> InstantPageLayout { var maybeLoadedContent: TelegramMediaWebpageLoadedContent? if case let .Loaded(content) = webPage.content { maybeLoadedContent = content @@ -871,7 +973,7 @@ public func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, instant var previousBlock: InstantPageBlock? for block in pageBlocks { - let blockLayout = layoutInstantPageBlock(webpage: webPage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false) + let blockLayout = layoutInstantPageBlock(webpage: webPage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: false) let spacing = spacingBetweenBlocks(upper: previousBlock, lower: block) let blockItems = blockLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing)) items.append(contentsOf: blockItems) diff --git a/submodules/InstantPageUI/Sources/InstantPageLayoutSpacings.swift b/submodules/InstantPageUI/Sources/InstantPageLayoutSpacings.swift index 6ad2c61e7c..51cc7d4886 100644 --- a/submodules/InstantPageUI/Sources/InstantPageLayoutSpacings.swift +++ b/submodules/InstantPageUI/Sources/InstantPageLayoutSpacings.swift @@ -21,7 +21,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> return 20.0 case (.title, .paragraph), (.authorDate, .paragraph): return 34.0 - case (.header, .paragraph), (.subheader, .paragraph): + case (.header, .paragraph), (.subheader, .paragraph), (.heading, .paragraph): return 25.0 case (.list, .paragraph): return 31.0 @@ -33,7 +33,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> return 20.0 case (.title, .list), (.authorDate, .list): return 34.0 - case (.header, .list), (.subheader, .list): + case (.header, .list), (.subheader, .list), (.heading, .list): return 31.0 case (.preformatted, .list): return 19.0 @@ -43,7 +43,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> return 19.0 case (_, .preformatted): return 20.0 - case (_, .header), (_, .subheader): + case (_, .header), (_, .subheader), (_, .heading): return 32.0 default: return 20.0 diff --git a/submodules/InstantPageUI/Sources/InstantPageTheme.swift b/submodules/InstantPageUI/Sources/InstantPageTheme.swift index 0c1b1d8153..dccc23d9fd 100644 --- a/submodules/InstantPageUI/Sources/InstantPageTheme.swift +++ b/submodules/InstantPageUI/Sources/InstantPageTheme.swift @@ -135,6 +135,32 @@ public final class InstantPageTheme { public func withUpdatedFontStyles(sizeMultiplier: CGFloat, forceSerif: Bool) -> InstantPageTheme { return InstantPageTheme(type: type, pageBackgroundColor: pageBackgroundColor, textCategories: self.textCategories.withUpdatedFontStyles(sizeMultiplier: sizeMultiplier, forceSerif: forceSerif), serif: forceSerif, codeBlockBackgroundColor: codeBlockBackgroundColor, linkColor: linkColor, textHighlightColor: textHighlightColor, linkHighlightColor: linkHighlightColor, markerColor: markerColor, panelBackgroundColor: panelBackgroundColor, panelHighlightedBackgroundColor: panelHighlightedBackgroundColor, panelPrimaryColor: panelPrimaryColor, panelSecondaryColor: panelSecondaryColor, panelAccentColor: panelAccentColor, tableBorderColor: tableBorderColor, tableHeaderColor: tableHeaderColor, controlColor: controlColor, imageTintColor: imageTintColor, overlayPanelColor: overlayPanelColor) } + + func headingTextAttributes(level: Int32, link: Bool) -> InstantPageTextAttributes { + let clampedLevel = max(Int32(3), min(level, Int32(6))) + let subheaderAttributes = self.textCategories.subheader + guard clampedLevel > 3 else { + return subheaderAttributes.withUnderline(link) + } + + let baseSize: CGFloat + switch clampedLevel { + case 4: + baseSize = 17.0 + case 5: + baseSize = 15.0 + default: + baseSize = 13.0 + } + + let sizeMultiplier = subheaderAttributes.font.size / 19.0 + let attributes = InstantPageTextAttributes( + font: InstantPageFont(style: .serif, size: floor(baseSize * sizeMultiplier), lineSpacingFactor: subheaderAttributes.font.lineSpacingFactor), + color: subheaderAttributes.color, + underline: subheaderAttributes.underline + ) + return attributes.withUnderline(link) + } } private let lightTheme = InstantPageTheme( diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGAttachmentCarouselItemView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGAttachmentCarouselItemView.h index 38d1fdfa9f..3ce8d62e49 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGAttachmentCarouselItemView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGAttachmentCarouselItemView.h @@ -35,7 +35,7 @@ @property (nonatomic) bool reminder; @property (nonatomic) bool forum; @property (nonatomic) bool isSuggesting; -@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t, bool)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, strong) NSArray *underlyingViews; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h index d1e0b2fcc0..7e1164ee05 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h @@ -63,7 +63,7 @@ typedef enum { @property (nonatomic, copy) void(^finishedTransitionOut)(void); @property (nonatomic, copy) void(^customPresentOverlayController)(TGOverlayController *(^)(id)); -@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t, bool)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); - (instancetype)initWithContext:(id)context saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h index 178f043270..1578e0f772 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h @@ -70,7 +70,7 @@ typedef enum @property (nonatomic, assign) bool forum; @property (nonatomic, assign) bool isSuggesting; -@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t, bool)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, assign) bool liveVideoUploadEnabled; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerController.h index c256f0832c..42ade02f88 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerController.h @@ -35,7 +35,7 @@ @property (nonatomic, assign) bool forum; @property (nonatomic, assign) bool isSuggesting; -@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t, bool)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, assign) CGFloat topInset; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerModernGalleryMixin.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerModernGalleryMixin.h index 24f4876030..46aacd32a1 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerModernGalleryMixin.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerModernGalleryMixin.h @@ -28,7 +28,7 @@ @property (nonatomic, copy) void (^editorOpened)(void); @property (nonatomic, copy) void (^editorClosed)(void); -@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t, bool)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); - (instancetype)initWithContext:(id)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder hasCoverButton:(bool)hasCoverButton stickersContext:(id)stickersContext; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h index 97fa637d8d..2031d9610e 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h @@ -9,7 +9,7 @@ @class TGModernGalleryController; -typedef void (^ _Nonnull TGPhotoVideoEditorSchedulePickerCompletion)(int32_t time); +typedef void (^ _Nonnull TGPhotoVideoEditorSchedulePickerCompletion)(int32_t time, bool silentPosting); typedef void (^ _Nonnull TGPhotoVideoEditorSchedulePicker)(bool media, TGPhotoVideoEditorSchedulePickerCompletion _Nonnull done); typedef void (^ _Nonnull TGPhotoVideoEditorCompletion)(id _Nonnull item, TGMediaEditingContext * _Nonnull editingContext, bool silentPosting, int32_t scheduleTime); diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGVideoMessageCaptureController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGVideoMessageCaptureController.h index 1538db8304..99af708e39 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGVideoMessageCaptureController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGVideoMessageCaptureController.h @@ -31,7 +31,7 @@ @property (nonatomic, copy) void(^didDismiss)(void); @property (nonatomic, copy) void(^didStop)(void); @property (nonatomic, copy) void(^displaySlowmodeTooltip)(void); -@property (nonatomic, copy) void (^presentScheduleController)(void (^)(int32_t)); +@property (nonatomic, copy) void (^presentScheduleController)(void (^)(int32_t, bool)); - (instancetype)initWithContext:(id)context forStory:(bool)forStory assets:(TGVideoMessageCaptureControllerAssets *)assets transitionInView:(UIView *(^)(void))transitionInView parentController:(TGViewController *)parentController controlsFrame:(CGRect)controlsFrame isAlreadyLocked:(bool (^)(void))isAlreadyLocked liveUploadInterface:(id)liveUploadInterface pallete:(TGModernConversationInputMicPallete *)pallete slowmodeTimestamp:(int32_t)slowmodeTimestamp slowmodeView:(UIView *(^)(void))slowmodeView canSendSilently:(bool)canSendSilently canSchedule:(bool)canSchedule reminder:(bool)reminder; diff --git a/submodules/LegacyComponents/Sources/TGCameraController.m b/submodules/LegacyComponents/Sources/TGCameraController.m index fd9b44075e..3d9f789212 100644 --- a/submodules/LegacyComponents/Sources/TGCameraController.m +++ b/submodules/LegacyComponents/Sources/TGCameraController.m @@ -1656,7 +1656,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus if (strongSelf == nil) return; - strongSelf.presentScheduleController(true, ^(int32_t time) { + strongSelf.presentScheduleController(true, ^(int32_t time, bool silentPosting) { __strong TGCameraController *strongSelf = weakSelf; __strong TGMediaPickerGalleryModel *strongModel = weakModel; @@ -1678,7 +1678,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus [[NSUserDefaults standardUserDefaults] setObject:@(!strongSelf->_selectionContext.grouping) forKey:@"TG_mediaGroupingDisabled_v0"]; if (strongSelf.finishedWithResults != nil) - strongSelf.finishedWithResults(strongController, strongSelf->_selectionContext, strongSelf->_editingContext, item.asset, false, time); + strongSelf.finishedWithResults(strongController, strongSelf->_selectionContext, strongSelf->_editingContext, item.asset, silentPosting, time); [strongSelf _dismissTransitionForResultController:strongController]; }); diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m index 1522c48030..4ff21ec6d9 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m @@ -478,7 +478,7 @@ static TGVideoEditAdjustments *TGMediaAssetsPatchedLivePhotoAdjustments(PGPhotoE self.pickerController.isSuggesting = isSuggesting; } -- (void)setPresentScheduleController:(void (^)(bool, void (^)(int32_t)))presentScheduleController { +- (void)setPresentScheduleController:(void (^)(bool, void (^)(int32_t, bool)))presentScheduleController { _presentScheduleController = [presentScheduleController copy]; self.pickerController.presentScheduleController = presentScheduleController; } @@ -1890,8 +1890,8 @@ static TGVideoEditAdjustments *TGMediaAssetsPatchedLivePhotoAdjustments(PGPhotoE - (void)schedule:(bool)media { __weak TGMediaAssetsController *weakSelf = self; - self.presentScheduleController(media, ^(int32_t scheduleTime) { - [weakSelf completeWithCurrentItem:nil silentPosting:false scheduleTime:scheduleTime]; + self.presentScheduleController(media, ^(int32_t scheduleTime, bool silentPosting) { + [weakSelf completeWithCurrentItem:nil silentPosting:silentPosting scheduleTime:scheduleTime]; }); } diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m b/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m index a1f83e5124..35a79b3278 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m @@ -201,7 +201,7 @@ if (strongSelf == nil) return; - strongSelf.presentScheduleController(true, ^(int32_t time) { + strongSelf.presentScheduleController(true, ^(int32_t time, bool silentPosting) { __strong TGMediaPickerModernGalleryMixin *strongSelf = weakSelf; if (strongSelf == nil) return; @@ -209,7 +209,7 @@ strongSelf->_galleryModel.dismiss(true, false); if (strongSelf.completeWithItem != nil) - strongSelf.completeWithItem(item, false, time); + strongSelf.completeWithItem(item, silentPosting, time); }); }; controller.sendWithTimer = ^{ diff --git a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m index 5ebd25410c..c407675ed9 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m +++ b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m @@ -282,8 +282,8 @@ complete(false, 0x7ffffffe); }; sendController.schedule = ^{ - presentSchedulePicker(true, ^(int32_t time) { - complete(false, time); + presentSchedulePicker(true, ^(int32_t time, bool silentPosting) { + complete(silentPosting, time); }); }; [strongController presentViewController:sendController animated:false completion:nil]; diff --git a/submodules/LegacyComponents/Sources/TGVideoMessageCaptureController.m b/submodules/LegacyComponents/Sources/TGVideoMessageCaptureController.m index 3a410ff2d7..cba0bf530e 100644 --- a/submodules/LegacyComponents/Sources/TGVideoMessageCaptureController.m +++ b/submodules/LegacyComponents/Sources/TGVideoMessageCaptureController.m @@ -844,13 +844,13 @@ typedef enum } if (strongSelf.presentScheduleController) { - strongSelf.presentScheduleController(^(int32_t time) { + strongSelf.presentScheduleController(^(int32_t time, bool silentPosting) { __strong TGVideoMessageCaptureController *strongSelf = weakSelf; if (strongSelf == nil) { return; } - [strongSelf finishWithURL:strongSelf->_url dimensions:CGSizeMake(240.0f, 240.0f) duration:strongSelf->_duration liveUploadData:strongSelf->_liveUploadData thumbnailImage:strongSelf->_thumbnailImage isSilent:false scheduleTimestamp:time]; + [strongSelf finishWithURL:strongSelf->_url dimensions:CGSizeMake(240.0f, 240.0f) duration:strongSelf->_duration liveUploadData:strongSelf->_liveUploadData thumbnailImage:strongSelf->_thumbnailImage isSilent:silentPosting scheduleTimestamp:time]; _automaticDismiss = true; [strongSelf dismiss:false]; diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index 0fd7d992a4..d367a967c3 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -170,7 +170,7 @@ public func legacyMediaEditor( hasSilentPosting: Bool = false, hasSchedule: Bool = false, reminder: Bool = false, - presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }, + presentSchedulePicker: @escaping (Bool, @escaping (Int32, Bool) -> Void) -> Void = { _, _ in }, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, Bool) -> Void, present: @escaping (ViewController, Any?) -> Void ) { @@ -213,7 +213,7 @@ public func legacyMediaEditor( legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true } - let schedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { media, done in + let schedulePicker: (Bool, @escaping (Int32, Bool) -> Void) -> Void = { media, done in presentSchedulePicker(media, done) } let appeared: () -> Void = { @@ -322,7 +322,7 @@ public func legacyAttachmentMenu( presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentJpegConversionAlert: @escaping (@escaping (Bool) -> Void) -> Void, - presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, + presentSchedulePicker: @escaping (Bool, @escaping (Int32, Bool) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, @@ -431,8 +431,8 @@ public func legacyAttachmentMenu( carouselItem.hasSchedule = hasSchedule carouselItem.reminder = peer?.id == context.account.peerId carouselItem.presentScheduleController = { media, done in - presentSchedulePicker(media, { time in - done?(time) + presentSchedulePicker(media, { time, silentPosting in + done?(time, silentPosting) }) } carouselItem.presentTimerController = { done in diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift index 17ab15a722..a4ebc8517e 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift @@ -20,7 +20,7 @@ public func guessMimeTypeByFileExtension(_ ext: String) -> String { return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary" } -public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: NSAttributedString, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) { +public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: NSAttributedString, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32, Bool) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) { let paintStickersContext = LegacyPaintStickersContext(context: context) paintStickersContext.captionPanelView = { return getCaptionPanelView() @@ -43,8 +43,8 @@ public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, co controller.hasCoverButton = true } controller.presentScheduleController = { media, done in - presentSchedulePicker(media, { time in - done?(time) + presentSchedulePicker(media, { time, silentPosting in + done?(time, silentPosting) }) } controller.presentTimerController = { done in diff --git a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift index 01ecb788f3..a2da740107 100644 --- a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift +++ b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift @@ -131,7 +131,7 @@ func presentLegacyMediaPickerGallery( transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?, @escaping () -> Void) -> Void, - presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, + presentSchedulePicker: @escaping (Bool, @escaping (Int32, Bool) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, @@ -369,8 +369,8 @@ func presentLegacyMediaPickerGallery( }) } sheetController.schedule = { - presentSchedulePicker(true, { time in - completed(item.asset, false, time, { + presentSchedulePicker(true, { time, silentPosting in + completed(item.asset, silentPosting, time, { dismissImpl() }) }) diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 62e456fc28..8e176c8f43 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -248,7 +248,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att public weak var webSearchController: WebSearchController? public var openCamera: ((Any?) -> Void)? - public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in } + public var presentSchedulePicker: (Bool, @escaping (Int32, Bool) -> Void) -> Void = { _, _ in } public var presentTimerPicker: (@escaping (Int32) -> Void) -> Void = { _ in } public var presentWebSearch: (MediaGroupsScreen, Bool) -> Void = { _, _ in } public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil } @@ -2298,8 +2298,8 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att } }, schedule: { [weak self] parameters in if let strongSelf = self { - strongSelf.presentSchedulePicker(false, { [weak self] time in - self?.interaction?.sendSelected(nil, false, time, true, parameters, {}) + strongSelf.presentSchedulePicker(false, { [weak self] time, silentPosting in + self?.interaction?.sendSelected(nil, silentPosting, time, true, parameters, {}) }) } }, dismissInput: { [weak self] in diff --git a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift index a744c229dd..680b6eb9ee 100644 --- a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift +++ b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift @@ -476,7 +476,7 @@ public func notificationSoundSelectionController(context: AccountContext, update break } }), - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { }) ], parseMarkdown: true), in: .window(.root)) } diff --git a/submodules/PasswordSetupUI/Sources/SetupTwoStepVerificationControllerNode.swift b/submodules/PasswordSetupUI/Sources/SetupTwoStepVerificationControllerNode.swift index 692d1e07cf..aa64693954 100644 --- a/submodules/PasswordSetupUI/Sources/SetupTwoStepVerificationControllerNode.swift +++ b/submodules/PasswordSetupUI/Sources/SetupTwoStepVerificationControllerNode.swift @@ -697,7 +697,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode { }, transition: .animated(duration: 0.5, curve: .spring)) } if case let .enterEmail(enterEmailState, enterEmailEmail)? = self.innerState.data.state, case .create = enterEmailState, enterEmailEmail.isEmpty { - self.present(textAlertController(sharedContext: self.context.sharedContext, title: nil, text: self.presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.TwoStepAuth_EmailSkip, action: { + self.present(textAlertController(sharedContext: self.context.sharedContext, title: nil, text: self.presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.TwoStepAuth_EmailSkip, action: { continueImpl() })]), nil) } else { diff --git a/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift b/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift index 78bd4bfa78..cf77e35974 100644 --- a/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift +++ b/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift @@ -534,7 +534,7 @@ public final class TwoFactorDataInputScreen: ViewController { strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) }), - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) ]), in: .window(.root)) case let .passwordHint(recovery, password, doneText): if let recovery = recovery { @@ -550,7 +550,7 @@ public final class TwoFactorDataInputScreen: ViewController { } strongSelf.performRecovery(recovery: recovery, password: "", hint: "") }), - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) ]), in: .window(.root)) case let .rememberPassword(doneText): guard case let .authorized(engine) = strongSelf.engine else { diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index e433428491..32661edbe5 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -385,7 +385,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry { return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: "", textColor: .black), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: true), spacing: 0.0, clearType: enabled ? .always : .none, enabled: enabled, tag: ChannelAdminEntryTag.rank, sectionId: self.section, textUpdated: { updatedText in arguments.updateRank(text, updatedText) }, shouldUpdateText: { text in - if text.containsEmoji { + if text.containsGraphicEmoji { arguments.animateError() return false } @@ -1329,7 +1329,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD return current } - if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsEmoji { + if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsGraphicEmoji { errorImpl?() return } @@ -1361,7 +1361,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD } let effectiveRank = updateRank ?? currentRank - if effectiveRank?.containsEmoji ?? false { + if effectiveRank?.containsGraphicEmoji ?? false { errorImpl?() return } @@ -1436,7 +1436,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD return current } - if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsEmoji { + if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsGraphicEmoji { errorImpl?() return } @@ -1516,7 +1516,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD return current } - if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsEmoji { + if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsGraphicEmoji { errorImpl?() return } diff --git a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift index 2c0fe628f0..bbf69ed1ef 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift @@ -382,7 +382,7 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry { return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: "", textColor: .black), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: true), spacing: 0.0, clearType: enabled ? .always : .none, enabled: enabled, tag: ChannelBannedMemberEntryTag.rank, sectionId: self.section, textUpdated: { updatedText in arguments.updateRank(text, updatedText) }, shouldUpdateText: { text in - if text.containsEmoji { + if text.containsGraphicEmoji { arguments.animateError() return false } @@ -860,7 +860,7 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen updateRank = current.updatedRank?.trimmingCharacters(in: .whitespacesAndNewlines) return current } - if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsEmoji { + if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsGraphicEmoji { errorImpl?() return } diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index d03290333d..1ccf724f2f 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -534,6 +534,8 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB return strings.Channel_BanUser_PermissionSendVoiceMessage } else if right.contains(.banSendInstantVideos) { return strings.Channel_BanUser_PermissionSendVideoMessage + } else if right.contains(.banSendReactions) { + return strings.Channel_BanUser_PermissionSendReactions } else if right.contains(.banEditRank) { if defaultPermissions { return strings.Channel_BanUser_PermissionEditOwnRank @@ -568,6 +570,8 @@ func compactStringForGroupPermission(strings: PresentationStrings, right: Telegr return strings.GroupPermission_NoSendLinks } else if right.contains(.banSendPolls) { return strings.GroupPermission_NoSendPolls + } else if right.contains(.banSendReactions) { + return strings.GroupPermission_NoSendReactions } else if right.contains(.banChangeInfo) { return strings.GroupPermission_NoChangeInfo } else if right.contains(.banAddMembers) { @@ -595,6 +599,7 @@ private let internal_allPossibleGroupPermissionList: [(TelegramChatBannedRightsF (.banSendInstantVideos, .banMembers), (.banEmbedLinks, .banMembers), (.banSendPolls, .banMembers), + (.banSendReactions, .banMembers), (.banAddMembers, .banMembers), (.banPinMessages, .pinMessages), (.banManageTopics, .manageTopics), @@ -647,6 +652,7 @@ public func banSendMediaSubList() -> [(TelegramChatBannedRightsFlags, TelegramCh (.banSendInstantVideos, .banMembers), (.banEmbedLinks, .banMembers), (.banSendPolls, .banMembers), + (.banSendReactions, .banMembers) ] } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/CreatePasswordController.swift b/submodules/SettingsUI/Sources/Privacy and Security/CreatePasswordController.swift index d0b5427be0..e96125f1e7 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/CreatePasswordController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/CreatePasswordController.swift @@ -313,7 +313,7 @@ func createPasswordController(context: AccountContext, createPasswordContext: Cr } if emailAlert { - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: presentationData.strings.TwoStepAuth_EmailSkip, action: { + presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: presentationData.strings.TwoStepAuth_EmailSkip, action: { saveImpl() })]), nil) } else { diff --git a/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift b/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift index 2317be18fb..b85aaeea8c 100644 --- a/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift +++ b/submodules/SettingsUI/Sources/Terms of Service/TermsOfServiceController.swift @@ -118,7 +118,7 @@ public class TermsOfServiceController: ViewController, StandalonePresentableCont } strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.PrivacyPolicy_Decline, text: text, actions: [TextAlertAction(type: .destructiveAction, title: declineTitle, action: { self?.decline() - }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { + }), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { })], actionLayout: .vertical), in: .window(.root)) }, rightAction: { [weak self] in guard let strongSelf = self else { diff --git a/submodules/TelegramApi/Sources/Api40.swift b/submodules/TelegramApi/Sources/Api40.swift index caec6d9e63..6960f0e58b 100644 --- a/submodules/TelegramApi/Sources/Api40.swift +++ b/submodules/TelegramApi/Sources/Api40.swift @@ -5851,6 +5851,39 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func deleteParticipantReaction(peer: Api.InputPeer, msgId: Int32, participant: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-474482644) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + participant.serialize(buffer, true) + return (FunctionDescription(name: "messages.deleteParticipantReaction", parameters: [("peer", ConstructorParameterDescription(peer)), ("msgId", ConstructorParameterDescription(msgId)), ("participant", ConstructorParameterDescription(participant))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } +} +public extension Api.functions.messages { + static func deleteParticipantReactions(peer: Api.InputPeer, participant: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1598550792) + peer.serialize(buffer, true) + participant.serialize(buffer, true) + return (FunctionDescription(name: "messages.deleteParticipantReactions", parameters: [("peer", ConstructorParameterDescription(peer)), ("participant", ConstructorParameterDescription(participant))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.messages { static func deletePhoneCallHistory(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/FlatSerialization/Models/InstantPageBlock.fbs b/submodules/TelegramCore/FlatSerialization/Models/InstantPageBlock.fbs index 5822db8b5f..ec3372afa1 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/InstantPageBlock.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/InstantPageBlock.fbs @@ -34,7 +34,8 @@ union InstantPageBlock_Value { InstantPageBlock_Table, InstantPageBlock_Details, InstantPageBlock_RelatedArticles, - InstantPageBlock_Map + InstantPageBlock_Map, + InstantPageBlock_Heading } table InstantPageBlock { @@ -70,6 +71,7 @@ table InstantPageBlock_Paragraph { table InstantPageBlock_Preformatted { text:RichText (id: 0, required); + language:string (id: 1); } table InstantPageBlock_Footer { @@ -184,6 +186,11 @@ table InstantPageBlock_Map { caption:InstantPageCaption (id: 4, required); } +table InstantPageBlock_Heading { + text:RichText (id: 0, required); + level:int32 (id: 1); +} + table InstantPageCaption { text:RichText (id: 0, required); credit:RichText (id: 1, required); diff --git a/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift b/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift index 262901d2a0..7030b2176a 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift @@ -121,7 +121,7 @@ extension InstantPageBlock { self = .paragraph(RichText(apiText: text)) case let .pageBlockPreformatted(pageBlockPreformattedData): let text = pageBlockPreformattedData.text - self = .preformatted(RichText(apiText: text)) + self = .preformatted(text: RichText(apiText: text), language: nil) case let .pageBlockFooter(pageBlockFooterData): let text = pageBlockFooterData.text self = .footer(RichText(apiText: text)) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift index a721277bd6..83072ffdf0 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift @@ -32,6 +32,7 @@ private enum InstantPageBlockType: Int32 { case details = 25 case relatedArticles = 26 case map = 27 + case heading = 28 } private func decodeListItems(_ decoder: PostboxDecoder) -> [InstantPageListItem] { @@ -60,8 +61,9 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { case authorDate(author: RichText, date: Int32) case header(RichText) case subheader(RichText) + case heading(text: RichText, level: Int32) case paragraph(RichText) - case preformatted(RichText) + case preformatted(text: RichText, language: String?) case footer(RichText) case divider case anchor(String) @@ -97,10 +99,15 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { self = .header(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.subheader.rawValue: self = .subheader(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.heading.rawValue: + self = .heading(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, level: decoder.decodeInt32ForKey("l", orElse: 3)) case InstantPageBlockType.paragraph.rawValue: self = .paragraph(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.preformatted.rawValue: - self = .preformatted(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + self = .preformatted( + text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, + language: decoder.decodeOptionalStringForKey("l") + ) case InstantPageBlockType.footer.rawValue: self = .footer(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) case InstantPageBlockType.divider.rawValue: @@ -184,12 +191,21 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { case let .subheader(text): encoder.encodeInt32(InstantPageBlockType.subheader.rawValue, forKey: "r") encoder.encodeObject(text, forKey: "t") + case let .heading(text, level): + encoder.encodeInt32(InstantPageBlockType.heading.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeInt32(level, forKey: "l") case let .paragraph(text): encoder.encodeInt32(InstantPageBlockType.paragraph.rawValue, forKey: "r") encoder.encodeObject(text, forKey: "t") - case let .preformatted(text): + case let .preformatted(text, language): encoder.encodeInt32(InstantPageBlockType.preformatted.rawValue, forKey: "r") encoder.encodeObject(text, forKey: "t") + if let language { + encoder.encodeString(language, forKey: "l") + } else { + encoder.encodeNil(forKey: "l") + } case let .footer(text): encoder.encodeInt32(InstantPageBlockType.footer.rawValue, forKey: "r") encoder.encodeObject(text, forKey: "t") @@ -374,14 +390,20 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { } else { return false } + case let .heading(lhsText, lhsLevel): + if case let .heading(rhsText, rhsLevel) = rhs, lhsText == rhsText, lhsLevel == rhsLevel { + return true + } else { + return false + } case let .paragraph(text): if case .paragraph(text) = rhs { return true } else { return false } - case let .preformatted(text): - if case .preformatted(text) = rhs { + case let .preformatted(lhsText, lhsLanguage): + if case let .preformatted(rhsText, rhsLanguage) = rhs, lhsText == rhsText, lhsLanguage == rhsLanguage { return true } else { return false @@ -545,6 +567,11 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { throw FlatBuffersError.missingRequiredField() } self = .subheader(try RichText(flatBuffersObject: value.text)) + case .instantpageblockHeading: + guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Heading.self) else { + throw FlatBuffersError.missingRequiredField() + } + self = .heading(text: try RichText(flatBuffersObject: value.text), level: value.level) case .instantpageblockParagraph: guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Paragraph.self) else { throw FlatBuffersError.missingRequiredField() @@ -554,7 +581,7 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Preformatted.self) else { throw FlatBuffersError.missingRequiredField() } - self = .preformatted(try RichText(flatBuffersObject: value.text)) + self = .preformatted(text: try RichText(flatBuffersObject: value.text), language: value.language) case .instantpageblockFooter: guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Footer.self) else { throw FlatBuffersError.missingRequiredField() @@ -698,17 +725,28 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable { let start = TelegramCore_InstantPageBlock_Subheader.startInstantPageBlock_Subheader(&builder) TelegramCore_InstantPageBlock_Subheader.add(text: textOffset, &builder) offset = TelegramCore_InstantPageBlock_Subheader.endInstantPageBlock_Subheader(&builder, start: start) + case let .heading(text, level): + valueType = .instantpageblockHeading + let textOffset = text.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_InstantPageBlock_Heading.startInstantPageBlock_Heading(&builder) + TelegramCore_InstantPageBlock_Heading.add(text: textOffset, &builder) + TelegramCore_InstantPageBlock_Heading.add(level: level, &builder) + offset = TelegramCore_InstantPageBlock_Heading.endInstantPageBlock_Heading(&builder, start: start) case let .paragraph(text): valueType = .instantpageblockParagraph let textOffset = text.encodeToFlatBuffers(builder: &builder) let start = TelegramCore_InstantPageBlock_Paragraph.startInstantPageBlock_Paragraph(&builder) TelegramCore_InstantPageBlock_Paragraph.add(text: textOffset, &builder) offset = TelegramCore_InstantPageBlock_Paragraph.endInstantPageBlock_Paragraph(&builder, start: start) - case let .preformatted(text): + case let .preformatted(text, language): valueType = .instantpageblockPreformatted let textOffset = text.encodeToFlatBuffers(builder: &builder) + let languageOffset = language.flatMap { builder.create(string: $0) } let start = TelegramCore_InstantPageBlock_Preformatted.startInstantPageBlock_Preformatted(&builder) TelegramCore_InstantPageBlock_Preformatted.add(text: textOffset, &builder) + if let languageOffset { + TelegramCore_InstantPageBlock_Preformatted.add(language: languageOffset, &builder) + } offset = TelegramCore_InstantPageBlock_Preformatted.endInstantPageBlock_Preformatted(&builder, start: start) case let .footer(text): valueType = .instantpageblockFooter diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChatBannedRights.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChatBannedRights.swift index f0ca1387f8..628c94ccd3 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChatBannedRights.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChatBannedRights.swift @@ -32,6 +32,7 @@ public struct TelegramChatBannedRightsFlags: OptionSet, Hashable { public static let banSendVoice = TelegramChatBannedRightsFlags(rawValue: 1 << 23) public static let banSendFiles = TelegramChatBannedRightsFlags(rawValue: 1 << 24) public static let banSendText = TelegramChatBannedRightsFlags(rawValue: 1 << 25) + public static let banSendReactions = TelegramChatBannedRightsFlags(rawValue: 1 << 27) public static let banEditRank = TelegramChatBannedRightsFlags(rawValue: 1 << 26) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift index 001fcc1282..3d37e36ab1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift @@ -76,6 +76,44 @@ func _internal_deleteAllMessagesWithForwardAuthor(transaction: Transaction, medi } } +func _internal_deleteAllReactionsWithAuthor(account: Account, peerId: PeerId, authorId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> (Peer?, Peer?) in + return (transaction.getPeer(peerId), transaction.getPeer(authorId)) + } + |> mapToSignal { peer, author in + guard let inputPeer = peer.flatMap(apiInputPeer), let inputAuthor = author.flatMap(apiInputPeer) else { + return .complete() + } + return account.network.request(Api.functions.messages.deleteParticipantReactions(peer: inputPeer, participant: inputAuthor)) + |> ignoreValues + |> `catch` { _ -> Signal in + return .complete() + } + } +} + +func _internal_deleteReaction(account: Account, messageId: MessageId, authorId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> (Peer?, Peer?) in + return (transaction.getPeer(messageId.peerId), transaction.getPeer(authorId)) + } + |> mapToSignal { peer, author in + guard let inputPeer = peer.flatMap(apiInputPeer), let inputAuthor = author.flatMap(apiInputPeer) else { + return .complete() + } + return account.network.request(Api.functions.messages.deleteParticipantReaction(peer: inputPeer, msgId: messageId.id, participant: inputAuthor)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates { + account.stateManager.addUpdates(updates) + } + return .complete() + } + } +} + func _internal_clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, threadId: Int64?, namespaces: MessageIdNamespaces) { if peerId.namespace == Namespaces.Peer.SecretChat { var resourceIds: [MediaResourceId] = [] diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 849790ac9a..8670dbab50 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -169,6 +169,14 @@ public extension TelegramEngine { } |> ignoreValues } + + public func deleteAllReactionsWithAuthor(peerId: EnginePeer.Id, authorId: EnginePeer.Id) -> Signal { + return _internal_deleteAllReactionsWithAuthor(account: self.account, peerId: peerId, authorId: authorId) + } + + public func deleteReaction(peerId: EnginePeer.Id, messageId: EngineMessage.Id, authorId: EnginePeer.Id) -> Signal { + return _internal_deleteReaction(account: self.account, messageId: messageId, authorId: authorId) + } public func clearCallHistory(forEveryone: Bool) -> Signal { return _internal_clearCallHistory(account: self.account, forEveryone: forEveryone) diff --git a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift index 636318a5c4..5396505457 100644 --- a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift +++ b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift @@ -29,6 +29,7 @@ struct MediaRight: OptionSet, Hashable { static let videoMessages = MediaRight(rawValue: 1 << 6) static let links = MediaRight(rawValue: 1 << 7) static let polls = MediaRight(rawValue: 1 << 8) + static let reactions = MediaRight(rawValue: 1 << 9) } extension MediaRight { @@ -75,7 +76,8 @@ private func rightsFromBannedRights(_ rights: TelegramChatBannedRightsFlags) -> .voiceMessages, .videoMessages, .links, - .polls + .polls, + .reactions ] if rights.contains(.banSendText) { @@ -168,6 +170,9 @@ private func rightFlagsFromRights(participantRights: ParticipantRight, mediaRigh if !mediaRights.contains(.polls) { result.insert(.banSendPolls) } + if !mediaRights.contains(.reactions) { + result.insert(.banSendReactions) + } return result } @@ -181,7 +186,8 @@ private let allMediaRightItems: [MediaRight] = [ .voiceMessages, .videoMessages, .links, - .polls + .polls, + .reactions ] private enum AdminUserActionOptionSection { @@ -821,6 +827,8 @@ private final class AdminUserActionsContentComponent: Component { mediaItemTitle = component.strings.Channel_BanUser_PermissionEmbedLinks case .polls: mediaItemTitle = component.strings.Channel_BanUser_PermissionSendPolls + case .reactions: + mediaItemTitle = component.strings.Channel_BanUser_PermissionSendReactions default: continue mediaRightsLoop } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index c9c88568c6..eb5bfb2f56 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -2619,14 +2619,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI switch authorRank { case let .creator(rank): if let rank, !rank.isEmpty { - string = rank.trimmingEmojis + string = rank } else { string = item.presentationData.strings.Conversation_Owner } rankBadgeColor = UIColor(rgb: 0x956ac8) case let .admin(rank): if let rank, !rank.isEmpty { - string = rank.trimmingEmojis + string = rank } else { string = item.presentationData.strings.Conversation_Admin } @@ -2637,7 +2637,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI string = item.presentationData.strings.Chat_TagPlaceholder defaultRankColor = defaultRankColor.withMultipliedAlpha(0.5) } else { - string = rank.trimmingEmojis + string = rank } } else { string = "" diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index 8edb6af71b..92ecd7dc37 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -2634,7 +2634,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg size: CGSize(width: baseWidth, height: panelHeight) ) - let audioRecordingTimeFrame = CGRect(origin: CGPoint(x: hideOffset.x + leftInset + leftMenuInset + 8.0 + 34.0, y: (accessoryPanel != nil ? 52.0 : 0.0) + panelHeight - minimalHeight + floor((minimalHeight - audioRecordingTimeSize.height) / 2.0) + 1.0 - UIScreenPixel), size: audioRecordingTimeSize) + let audioRecordingTimeFrame = CGRect(origin: CGPoint(x: hideOffset.x + leftInset + leftMenuInset + 8.0 + 22.0, y: (accessoryPanel != nil ? 52.0 : 0.0) + panelHeight - minimalHeight + floor((minimalHeight - audioRecordingTimeSize.height) / 2.0) + 1.0 - UIScreenPixel), size: audioRecordingTimeSize) if animateTimeSlideIn { var previousAudioRecordingTimeFrame = audioRecordingTimeFrame diff --git a/submodules/TelegramUI/Components/ChatParticipantRightsScreen/Sources/ChatParticipantRightsScreen.swift b/submodules/TelegramUI/Components/ChatParticipantRightsScreen/Sources/ChatParticipantRightsScreen.swift index 6bbc4ad256..4e3a5f6995 100644 --- a/submodules/TelegramUI/Components/ChatParticipantRightsScreen/Sources/ChatParticipantRightsScreen.swift +++ b/submodules/TelegramUI/Components/ChatParticipantRightsScreen/Sources/ChatParticipantRightsScreen.swift @@ -260,7 +260,7 @@ private final class ChatParticipantRightsContent: CombinedComponent { state.updated(transition: .easeInOut(duration: 0.2)) }, shouldUpdateText: { [weak state] text in - if text.containsEmoji { + if text.containsGraphicEmoji { state?.animateError() return false } diff --git a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift index c1e232f39c..1a6da87630 100644 --- a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift +++ b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeScreen.swift @@ -39,6 +39,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component { let currentRepeatPeriod: Int32? let suggestedTime: Int32? let minimalTime: Int32? + let silentPosting: Bool let externalState: ExternalState let dismiss: () -> Void @@ -49,6 +50,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component { currentRepeatPeriod: Int32?, suggestedTime: Int32?, minimalTime: Int32?, + silentPosting: Bool, externalState: ExternalState, dismiss: @escaping () -> Void ) { @@ -58,6 +60,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component { self.currentRepeatPeriod = currentRepeatPeriod self.suggestedTime = suggestedTime self.minimalTime = minimalTime + self.silentPosting = silentPosting self.externalState = externalState self.dismiss = dismiss } @@ -222,6 +225,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component { self.environment = environment if self.component == nil { + self.isSilentPosting = component.silentPosting switch component.mode { case .format, .search: self.minDate = Date(timeIntervalSince1970: 0.0) @@ -561,7 +565,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component { controller.completion( ChatScheduleTimeScreen.Result( time: Int32(self.date?.timeIntervalSince1970 ?? 0), - repeatPeriod: self.repeatPeriod + repeatPeriod: self.repeatPeriod, + silentPosting: self.isSilentPosting ) ) component.dismiss() @@ -609,7 +614,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component { controller.completion( ChatScheduleTimeScreen.Result( time: 0, - repeatPeriod: nil + repeatPeriod: nil, + silentPosting: false ) ) component.dismiss() @@ -650,7 +656,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component { controller.completion( ChatScheduleTimeScreen.Result( time: scheduleWhenOnlineTimestamp, - repeatPeriod: nil + repeatPeriod: nil, + silentPosting: self.isSilentPosting ) ) component.dismiss() @@ -918,6 +925,7 @@ private final class ChatScheduleTimeScreenComponent: Component { let currentRepeatPeriod: Int32? let suggestedTime: Int32? let minimalTime: Int32? + let silentPosting: Bool init( context: AccountContext, @@ -925,7 +933,8 @@ private final class ChatScheduleTimeScreenComponent: Component { currentTime: Int32?, currentRepeatPeriod: Int32?, suggestedTime: Int32?, - minimalTime: Int32? + minimalTime: Int32?, + silentPosting: Bool ) { self.context = context self.mode = mode @@ -933,6 +942,7 @@ private final class ChatScheduleTimeScreenComponent: Component { self.currentRepeatPeriod = currentRepeatPeriod self.suggestedTime = suggestedTime self.minimalTime = minimalTime + self.silentPosting = silentPosting } static func ==(lhs: ChatScheduleTimeScreenComponent, rhs: ChatScheduleTimeScreenComponent) -> Bool { @@ -951,6 +961,9 @@ private final class ChatScheduleTimeScreenComponent: Component { if lhs.minimalTime != rhs.minimalTime { return false } + if lhs.silentPosting != rhs.silentPosting { + return false + } return true } @@ -1005,6 +1018,7 @@ private final class ChatScheduleTimeScreenComponent: Component { currentRepeatPeriod: component.currentRepeatPeriod, suggestedTime: component.suggestedTime, minimalTime: component.minimalTime, + silentPosting: component.silentPosting, externalState: self.contentExternalState, dismiss: { [weak self] in guard let self else { @@ -1080,6 +1094,13 @@ public class ChatScheduleTimeScreen: ViewControllerComponentContainer { public struct Result { public let time: Int32 public let repeatPeriod: Int32? + public let silentPosting: Bool + + public init(time: Int32, repeatPeriod: Int32?, silentPosting: Bool = false) { + self.time = time + self.repeatPeriod = repeatPeriod + self.silentPosting = silentPosting + } } fileprivate let completion: (Result) -> Void @@ -1091,6 +1112,7 @@ public class ChatScheduleTimeScreen: ViewControllerComponentContainer { currentRepeatPeriod: Int32? = nil, suggestedTime: Int32? = nil, minimalTime: Int32? = nil, + silentPosting: Bool = false, isDark: Bool, completion: @escaping (Result) -> Void ) { @@ -1102,7 +1124,8 @@ public class ChatScheduleTimeScreen: ViewControllerComponentContainer { currentTime: currentTime, currentRepeatPeriod: currentRepeatPeriod, suggestedTime: suggestedTime, - minimalTime: minimalTime + minimalTime: minimalTime, + silentPosting: silentPosting ), navigationBarAppearance: .none, theme: isDark ? .dark : .default) self.statusBar.statusBarStyle = .Ignore diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 0bb4a53162..f9e3617e60 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -1407,6 +1407,7 @@ public final class EmojiPagerContentComponent: Component { private var vibrancyClippingView: UIView private var vibrancyEffectView: UIView? public private(set) var mirrorContentClippingView: UIView? + private let mirrorScrollViewClippingView: UIView private let mirrorContentScrollView: UIView private var warpView: WarpView? private var mirrorContentWarpView: WarpView? @@ -1459,6 +1460,9 @@ public final class EmojiPagerContentComponent: Component { private var longTapRecognizer: UILongPressGestureRecognizer? private func hasSameContentId(_ lhs: ContentId?, _ rhs: ContentId?) -> Bool { + if let rhs, rhs.version < 2 { + return false + } return lhs?.id == rhs?.id } @@ -1480,6 +1484,9 @@ public final class EmojiPagerContentComponent: Component { self.scrollViewClippingView = UIView() self.scrollViewClippingView.clipsToBounds = true + self.mirrorScrollViewClippingView = UIView() + self.mirrorScrollViewClippingView.clipsToBounds = true + self.mirrorContentScrollView = UIView() self.mirrorContentScrollView.layer.anchorPoint = CGPoint() self.mirrorContentScrollView.clipsToBounds = true @@ -1519,6 +1526,8 @@ public final class EmojiPagerContentComponent: Component { self.addSubview(self.scrollViewClippingView) self.scrollViewClippingView.addSubview(self.scrollView) + self.mirrorScrollViewClippingView.addSubview(self.mirrorContentScrollView) + self.scrollView.addSubview(self.placeholdersContainerView) let contextGesture = ContextGesture(target: self, action: #selector(self.tapGesture(_:))) @@ -1658,6 +1667,16 @@ public final class EmojiPagerContentComponent: Component { fatalError("init(coder:) has not been implemented") } + private var mirrorOverlayContainerView: UIView? { + if let mirrorContentClippingView = self.mirrorContentClippingView { + return mirrorContentClippingView + } else if let vibrancyEffectView = self.vibrancyEffectView { + return vibrancyEffectView + } else { + return nil + } + } + func updateIsWarpEnabled(isEnabled: Bool) { if isEnabled { if self.warpView == nil { @@ -1671,6 +1690,7 @@ public final class EmojiPagerContentComponent: Component { let mirrorContentWarpView = WarpView(frame: CGRect()) self.mirrorContentWarpView = mirrorContentWarpView + self.mirrorScrollViewClippingView.addSubview(mirrorContentWarpView) mirrorContentWarpView.contentView.addSubview(self.mirrorContentScrollView) } } else { @@ -1683,12 +1703,7 @@ public final class EmojiPagerContentComponent: Component { if let mirrorContentWarpView = self.mirrorContentWarpView { self.mirrorContentWarpView = nil - if let mirrorContentClippingView = self.mirrorContentClippingView { - mirrorContentClippingView.addSubview(self.mirrorContentScrollView) - } else if let vibrancyEffectView = self.vibrancyEffectView { - vibrancyEffectView.addSubview(self.mirrorContentScrollView) - } - + self.mirrorScrollViewClippingView.addSubview(self.mirrorContentScrollView) mirrorContentWarpView.removeFromSuperview() } } @@ -4117,12 +4132,11 @@ public final class EmojiPagerContentComponent: Component { mirrorContentClippingView = UIView() mirrorContentClippingView.clipsToBounds = false self.mirrorContentClippingView = mirrorContentClippingView - - if let mirrorContentWarpView = self.mirrorContentWarpView { - mirrorContentClippingView.addSubview(mirrorContentWarpView) - } else { - mirrorContentClippingView.addSubview(self.mirrorContentScrollView) - } + } + if self.mirrorScrollViewClippingView.superview !== mirrorContentClippingView { + mirrorContentClippingView.insertSubview(self.mirrorScrollViewClippingView, at: 0) + } else { + mirrorContentClippingView.sendSubviewToBack(self.mirrorScrollViewClippingView) } let clippingFrame = CGRect(origin: CGPoint(x: 0.0, y: pagerEnvironment.containerInsets.top), size: CGSize(width: backgroundFrame.width, height: backgroundFrame.height)) @@ -4146,9 +4160,13 @@ public final class EmojiPagerContentComponent: Component { } self.vibrancyEffectView = vibrancyEffectView self.backgroundTintView.mask = vibrancyEffectView - self.vibrancyClippingView.addSubview(self.mirrorContentScrollView) vibrancyEffectView.addSubview(self.vibrancyClippingView) } + if self.mirrorScrollViewClippingView.superview !== self.vibrancyClippingView { + self.vibrancyClippingView.insertSubview(self.mirrorScrollViewClippingView, at: 0) + } else { + self.vibrancyClippingView.sendSubviewToBack(self.mirrorScrollViewClippingView) + } } if component.hideBackground { @@ -4551,6 +4569,9 @@ public final class EmojiPagerContentComponent: Component { transition.setFrame(view: self.vibrancyClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize)) transition.setBounds(view: self.vibrancyClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize)) + transition.setFrame(view: self.mirrorScrollViewClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize)) + transition.setBounds(view: self.mirrorScrollViewClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize)) + let previousSize = self.scrollView.bounds.size self.scrollView.bounds = CGRect(origin: self.scrollView.bounds.origin, size: scrollSize) @@ -4714,11 +4735,9 @@ public final class EmojiPagerContentComponent: Component { if self.isSearchActivated { if visibleSearchHeader.superview != self { self.addSubview(visibleSearchHeader) - if self.mirrorContentClippingView != nil { - self.mirrorContentClippingView?.addSubview(visibleSearchHeader.tintContainerView) - } else { - self.mirrorContentScrollView.superview?.superview?.addSubview(visibleSearchHeader.tintContainerView) - } + } + if let mirrorOverlayContainerView = self.mirrorOverlayContainerView, visibleSearchHeader.tintContainerView.superview !== mirrorOverlayContainerView { + mirrorOverlayContainerView.addSubview(visibleSearchHeader.tintContainerView) } } else { /*if useOpaqueTheme { @@ -4779,7 +4798,7 @@ public final class EmojiPagerContentComponent: Component { self.visibleSearchHeader = visibleSearchHeader if self.isSearchActivated { self.addSubview(visibleSearchHeader) - self.mirrorContentClippingView?.addSubview(visibleSearchHeader.tintContainerView) + self.mirrorOverlayContainerView?.addSubview(visibleSearchHeader.tintContainerView) } else { self.scrollView.addSubview(visibleSearchHeader) self.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index c2eb599ab8..7561222c9b 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -620,7 +620,7 @@ private final class GiftViewSheetContent: CombinedComponent { title: presentationData.strings.Gift_Convert_Title, text: text, actions: [ - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Gift_Convert_Convert, action: { [weak self, weak controller, weak navigationController] in guard let self else { return diff --git a/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift b/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift index 1b55e61013..0eb250bf4d 100644 --- a/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift +++ b/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift @@ -11,7 +11,7 @@ import ShareController import LegacyUI import LegacyMediaPickerUI -public func presentedLegacyCamera(context: AccountContext, peer: Peer?, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, enablePhoto: Bool, enableVideo: Bool, sendPaidMessageStars: Int64 = 0, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ChatSendMessageActionSheetController.SendParameters?) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) { +public func presentedLegacyCamera(context: AccountContext, peer: Peer?, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, enablePhoto: Bool, enableVideo: Bool, sendPaidMessageStars: Int64 = 0, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ChatSendMessageActionSheetController.SendParameters?) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32, Bool) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme) legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait) @@ -45,8 +45,8 @@ public func presentedLegacyCamera(context: AccountContext, peer: Peer?, chatLoca } controller.presentScheduleController = { _, done in - presentSchedulePicker(true, { time in - done?(time) + presentSchedulePicker(true, { time, silentPosting in + done?(time, silentPosting) }) } controller.presentTimerController = { done in diff --git a/submodules/TelegramUI/Components/LegacyInstantVideoController/Sources/LegacyInstantVideoController.swift b/submodules/TelegramUI/Components/LegacyInstantVideoController/Sources/LegacyInstantVideoController.swift index c856324ebd..8e8c81eb1d 100644 --- a/submodules/TelegramUI/Components/LegacyInstantVideoController/Sources/LegacyInstantVideoController.swift +++ b/submodules/TelegramUI/Components/LegacyInstantVideoController/Sources/LegacyInstantVideoController.swift @@ -133,7 +133,7 @@ public func legacyInputMicPalette(from theme: PresentationTheme) -> TGModernConv return TGModernConversationInputMicPallete(dark: theme.overallDarkAppearance, buttonColor: inputPanelTheme.actionControlFillColor, iconColor: inputPanelTheme.actionControlForegroundColor, backgroundColor: theme.rootController.navigationBar.opaqueBackgroundColor, borderColor: inputPanelTheme.panelSeparatorColor, lock: inputPanelTheme.panelControlAccentColor, textColor: inputPanelTheme.primaryTextColor, secondaryTextColor: inputPanelTheme.secondaryTextColor, recording: inputPanelTheme.mediaRecordingDotColor) } -public func legacyInstantVideoController(theme: PresentationTheme, forStory: Bool, panelFrame: CGRect, context: AccountContext, peerId: PeerId, slowmodeState: ChatSlowmodeState?, hasSchedule: Bool, send: @escaping (InstantVideoController, EnqueueMessage?) -> Void, displaySlowmodeTooltip: @escaping (UIView, CGRect) -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void) -> InstantVideoController { +public func legacyInstantVideoController(theme: PresentationTheme, forStory: Bool, panelFrame: CGRect, context: AccountContext, peerId: PeerId, slowmodeState: ChatSlowmodeState?, hasSchedule: Bool, send: @escaping (InstantVideoController, EnqueueMessage?) -> Void, displaySlowmodeTooltip: @escaping (UIView, CGRect) -> Void, presentSchedulePicker: @escaping (@escaping (Int32, Bool) -> Void) -> Void) -> InstantVideoController { let isSecretChat = peerId.namespace == Namespaces.Peer.SecretChat let legacyController = InstantVideoController(presentation: .custom, theme: theme) @@ -166,8 +166,8 @@ public func legacyInstantVideoController(theme: PresentationTheme, forStory: Boo return node }, canSendSilently: !isSecretChat, canSchedule: hasSchedule, reminder: peerId == context.account.peerId)! controller.presentScheduleController = { done in - presentSchedulePicker { time in - done?(time) + presentSchedulePicker { time, silentPosting in + done?(time, silentPosting) } } controller.finishedWithVideo = { [weak legacyController] videoUrl, previewImage, _, duration, dimensions, liveUploadData, adjustments, isSilent, scheduleTimestamp in diff --git a/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift b/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift index c9fcea3e0a..0a4c7ffdcc 100644 --- a/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift +++ b/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift @@ -1116,7 +1116,7 @@ public func notificationPeerExceptionController( break } }), - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { }) ], parseMarkdown: true), in: .window(.root)) } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 62c731b5fe..40e9900476 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -4533,7 +4533,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro TextAlertAction(type: .destructiveAction, title: actionText, action: { self?.deletePeerChat(peer: peer._asPeer(), globally: delete) }), - TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }) ], parseMarkdown: true), in: .window(.root)) }) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift index 9f1663f763..e1ad235d1c 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift @@ -5177,7 +5177,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr public func presentDeleteBotPreviewLanguage() { self.parentController?.present(textAlertController(context: self.context, title: self.presentationData.strings.BotPreviews_DeleteTranslationAlert_Title, text: self.presentationData.strings.BotPreviews_DeleteTranslationAlert_Text, actions: [ - TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.Common_OK, action: { [weak self] in guard let self else { diff --git a/submodules/TelegramUI/Components/ShareExtensionContext/BUILD b/submodules/TelegramUI/Components/ShareExtensionContext/BUILD index 47e6c76e66..1b1e2be9d1 100644 --- a/submodules/TelegramUI/Components/ShareExtensionContext/BUILD +++ b/submodules/TelegramUI/Components/ShareExtensionContext/BUILD @@ -33,6 +33,7 @@ swift_library( "//submodules/ActivityIndicator", "//submodules/DebugSettingsUI", "//submodules/ManagedFile", + "//submodules/ContextUI", "//submodules/TelegramUI/Components/TelegramUIDeclareEncodables", "//submodules/TelegramUI/Components/AnimationCache", "//submodules/TelegramUI/Components/MultiAnimationRenderer", @@ -41,6 +42,7 @@ swift_library( "//submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods", "//submodules/TelegramUI/Components/PeerSelectionController", "//submodules/TelegramUI/Components/ContextMenuScreen", + "//submodules/TelegramUI/Components/ContextControllerImpl", "//submodules/TelegramUI/Components/NavigationBarImpl", ], visibility = [ diff --git a/submodules/TelegramUI/Components/ShareExtensionContext/Sources/ShareExtensionContext.swift b/submodules/TelegramUI/Components/ShareExtensionContext/Sources/ShareExtensionContext.swift index c3b242c393..9ee724f9b4 100644 --- a/submodules/TelegramUI/Components/ShareExtensionContext/Sources/ShareExtensionContext.swift +++ b/submodules/TelegramUI/Components/ShareExtensionContext/Sources/ShareExtensionContext.swift @@ -34,6 +34,8 @@ import TelegramAccountAuxiliaryMethods import PeerSelectionController import ContextMenuScreen import NavigationBarImpl +import ContextUI +import ContextControllerImpl private var installedSharedLogger = false @@ -201,6 +203,18 @@ public class ShareRootControllerImpl { defaultNavigationBarImpl = { presentationData in return NavigationBarImpl(presentationData: presentationData) } + makeContextControllerImpl = { context, presentationData, configuration, recognizer, gesture, workaroundUseLegacyImplementation, disableScreenshots, hideReactionPanelTail in + return ContextControllerImpl( + context: context, + presentationData: presentationData, + configuration: configuration, + recognizer: recognizer, + gesture: gesture, + workaroundUseLegacyImplementation: workaroundUseLegacyImplementation, + disableScreenshots: disableScreenshots, + hideReactionPanelTail: hideReactionPanelTail + ) + } } deinit { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index e374ef17e8..90a57d5a3e 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -947,7 +947,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { }) } - func performSendContextResultAction(view: StoryItemSetContainerComponent.View, results: ChatContextResultCollection, result: ChatContextResult) { + func performSendContextResultAction(view: StoryItemSetContainerComponent.View, results: ChatContextResultCollection, result: ChatContextResult, silentPosting: Bool = false, scheduleTime: Int32? = nil) { guard let component = view.component else { return } @@ -987,6 +987,8 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { replyTo: nil, storyId: focusedStoryId, content: .contextResult(results, result), + silentPosting: silentPosting, + scheduleTime: scheduleTime, sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars ) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in Queue.mainQueue().after(0.3) { @@ -1140,8 +1142,8 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { guard let self, let view else { return } - self.presentScheduleTimePicker(view: view, peer: peer, completion: { time, repeatPeriod in - done(time) + self.presentScheduleTimePicker(view: view, peer: peer, completion: { time, repeatPeriod, silentPosting in + done(time, silentPosting) }) }))) } @@ -2292,8 +2294,8 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { guard let self, let view else { return } - self.presentScheduleTimePicker(view: view, peer: peer, style: media ? .media : .default, completion: { time, repeatPeriod in - done(time) + self.presentScheduleTimePicker(view: view, peer: peer, style: media ? .media : .default, completion: { time, repeatPeriod, silentPosting in + done(time, silentPosting) }) } controller.presentTimerPicker = { [weak self, weak view] done in @@ -2372,7 +2374,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { if let view, let component = view.component { let theme = component.theme let updatedPresentationData: (initial: PresentationData, signal: Signal) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }) - let controller = WebSearchController(context: component.context, updatedPresentationData: updatedPresentationData, peer: peer, chatLocation: .peer(id: peer.id), configuration: searchBotsConfiguration, mode: .media(attachment: false, completion: { [weak view] results, selectionState, editingState, silentPosting in + let controller = WebSearchController(context: component.context, updatedPresentationData: updatedPresentationData, peer: peer, chatLocation: .peer(id: peer.id), configuration: searchBotsConfiguration, mode: .media(attachment: false, completion: { [weak view] results, selectionState, editingState, silentPosting, scheduleTime in if let legacyController = legacyController { legacyController.dismiss() } @@ -2381,14 +2383,14 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { } legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { [weak view] result in if let strongSelf = self, let view { - strongSelf.enqueueChatContextResult(view: view, peer: peer, replyMessageId: replyMessageId, storyId: replyToStoryId, results: results, result: result, hideVia: true) + strongSelf.enqueueChatContextResult(view: view, peer: peer, replyMessageId: replyMessageId, storyId: replyToStoryId, results: results, result: result, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime) } }, enqueueMediaMessages: { [weak view] signals in if let strongSelf = self, let view { if editingMedia { strongSelf.editMessageMediaWithLegacySignals(view: view, signals: signals) } else { - strongSelf.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: replyMessageId, replyToStoryId: replyToStoryId, signals: signals, silentPosting: silentPosting) + strongSelf.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: replyMessageId, replyToStoryId: replyToStoryId, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime) } } }) @@ -2414,8 +2416,8 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { component.controller()?.present(textAlertController(context: component.context, updatedPresentationData: (presentationData, .single(presentationData)), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }, presentSchedulePicker: { [weak view] media, done in if let strongSelf = self, let view { - strongSelf.presentScheduleTimePicker(view: view, peer: peer, style: media ? .media : .default, completion: { time, repeatPeriod in - done(time) + strongSelf.presentScheduleTimePicker(view: view, peer: peer, style: media ? .media : .default, completion: { time, repeatPeriod, silentPosting in + done(time, silentPosting) }) } }, presentTimerPicker: { [weak view] done in @@ -2640,7 +2642,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { // component.controller()?.push(controller) } - private func enqueueChatContextResult(view: StoryItemSetContainerComponent.View, peer: EnginePeer, replyMessageId: EngineMessage.Id?, storyId: StoryId?, results: ChatContextResultCollection, result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, resetTextInputState: Bool = true) { + private func enqueueChatContextResult(view: StoryItemSetContainerComponent.View, peer: EnginePeer, replyMessageId: EngineMessage.Id?, storyId: StoryId?, results: ChatContextResultCollection, result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, scheduleTime: Int32? = nil, resetTextInputState: Bool = true) { if !canSendMessagesToPeer(peer._asPeer()) { return } @@ -2669,7 +2671,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { } } - sendMessage(nil) + sendMessage(scheduleTime) } private func presentWebSearch(view: StoryItemSetContainerComponent.View, activateOnDisplay: Bool = true, present: @escaping (ViewController, Any?) -> Void) { @@ -2686,14 +2688,14 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots()) |> deliverOnMainQueue).start(next: { [weak self, weak view] configuration in if let self { - let controller = WebSearchController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, chatLocation: .peer(id: peer.id), configuration: configuration, mode: .media(attachment: true, completion: { [weak self] results, selectionState, editingState, silentPosting in + let controller = WebSearchController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, chatLocation: .peer(id: peer.id), configuration: configuration, mode: .media(attachment: true, completion: { [weak self] results, selectionState, editingState, silentPosting, scheduleTime in legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { [weak self, weak view] result in if let self, let view { - self.performSendContextResultAction(view: view, results: results, result: result) + self.performSendContextResultAction(view: view, results: results, result: result, silentPosting: silentPosting, scheduleTime: scheduleTime) } }, enqueueMediaMessages: { [weak self, weak view] signals in if let self, let view, !signals.isEmpty { - self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: nil, replyToStoryId: StoryId(peerId: peer.id, id: storyId), signals: signals, silentPosting: false) + self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: nil, replyToStoryId: StoryId(peerId: peer.id, id: storyId), signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime) } }) }), activateOnDisplay: activateOnDisplay) @@ -2833,8 +2835,8 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { guard let self, let view else { return } - self.presentScheduleTimePicker(view: view, peer: peer, style: .media, completion: { time, repeatPeriod in - done(time) + self.presentScheduleTimePicker(view: view, peer: peer, style: .media, completion: { time, repeatPeriod, silentPosting in + done(time, silentPosting) }) }, presentTimerPicker: { [weak self, weak view] done in guard let self, let view else { @@ -2868,7 +2870,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { style: ChatScheduleTimeControllerStyle = .default, selectedTime: Int32? = nil, dismissByTapOutside: Bool = true, - completion: @escaping (Int32, Int32?) -> Void + completion: @escaping (Int32, Int32?, Bool) -> Void ) { guard let component = view.component else { return @@ -2889,16 +2891,25 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { sendWhenOnlineAvailable = false } - let mode: ChatScheduleTimeControllerMode + let mode: ChatScheduleTimeScreen.Mode //ChatScheduleTimeControllerMode if peer.id == component.context.account.peerId { mode = .reminders } else { - mode = .scheduledMessages(sendWhenOnlineAvailable: sendWhenOnlineAvailable) + mode = .scheduledMessages(peerId: peer.id, sendWhenOnlineAvailable: sendWhenOnlineAvailable) } - let theme = component.theme - let controller = ChatScheduleTimeController(context: component.context, updatedPresentationData: (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), mode: mode, style: style, currentTime: selectedTime, minimalTime: nil, dismissByTapOutside: dismissByTapOutside, completion: { time in - completion(time, nil) - }) + let controller = ChatScheduleTimeScreen( + context: component.context, + mode: mode, + currentTime: selectedTime, + currentRepeatPeriod: nil, + suggestedTime: nil, + minimalTime: nil, + silentPosting: false, + isDark: style == .media, + completion: { result in + completion(result.time, nil, result.silentPosting) + } + ) view.endEditing(true) view.component?.controller()?.present(controller, in: .window(.root)) }) diff --git a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift index 28039854e9..8e663ee071 100644 --- a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift +++ b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift @@ -441,7 +441,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { } }, error: { [weak self] _ in if let self, let controller = self.getController() { - controller.completion(nil, nil, nil) + controller.completion(nil, nil, nil, nil) } })) } @@ -1641,7 +1641,7 @@ public class VideoMessageCameraScreen: ViewController { fileprivate var allowLiveUpload: Bool fileprivate var viewOnceAvailable: Bool - fileprivate let completion: (EnqueueMessage?, Bool?, Int32?) -> Void + fileprivate let completion: (EnqueueMessage?, Bool?, Int32?, Int32?) -> Void private var audioSessionDisposable: Disposable? @@ -1794,7 +1794,7 @@ public class VideoMessageCameraScreen: ViewController { viewOnceAvailable: Bool, inputPanelFrame: (CGRect, Bool), chatNode: ASDisplayNode?, - completion: @escaping (EnqueueMessage?, Bool?, Int32?) -> Void + completion: @escaping (EnqueueMessage?, Bool?, Int32?, Int32?) -> Void ) { self.context = context self.updatedPresentationData = updatedPresentationData @@ -1833,7 +1833,7 @@ public class VideoMessageCameraScreen: ViewController { fileprivate var didSend = false fileprivate var lastActionTimestamp: Double? fileprivate var isSendingImmediately = false - public func sendVideoRecording(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, messageEffect: ChatSendMessageEffect? = nil) { + public func sendVideoRecording(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, repeatPeriod: Int32? = nil, messageEffect: ChatSendMessageEffect? = nil) { guard !self.didSend else { return } @@ -1845,7 +1845,7 @@ public class VideoMessageCameraScreen: ViewController { } if case .none = self.cameraState.recording, self.node.results.isEmpty { - self.completion(nil, nil, nil) + self.completion(nil, nil, nil, nil) return } @@ -1859,7 +1859,7 @@ public class VideoMessageCameraScreen: ViewController { self.waitingForNextResult = true self.node.stopRecording.invoke(Void()) } else { - self.completion(nil, nil, nil) + self.completion(nil, nil, nil, nil) return } } @@ -1889,7 +1889,7 @@ public class VideoMessageCameraScreen: ViewController { } if duration < 1.0 { - self.completion(nil, nil, nil) + self.completion(nil, nil, nil, nil) return } @@ -1998,7 +1998,7 @@ public class VideoMessageCameraScreen: ViewController { localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [] - ), silentPosting, scheduleTime) + ), silentPosting, scheduleTime, repeatPeriod) }) }) } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift index 07011b5379..741427088e 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift @@ -35,12 +35,12 @@ extension ChatControllerImpl { guard let self else { return } - self.presentScheduleTimePicker(style: .media, completion: { [weak self] time, _ in + self.presentScheduleTimePicker(style: .media, completion: { [weak self] result in guard let self else { return } - done(time) - if self.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if self.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { self.openScheduledMessages() } }) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index bf6c235c20..61611b0b0a 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -1007,7 +1007,8 @@ extension ChatControllerImpl { } } - let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: silentPosting ?? false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone) + let effectiveSilentPosting = silentPosting ?? strongSelf.presentationInterfaceState.interfaceState.silentPosting + let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: effectiveSilentPosting, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone) var forwardedMessages: [[EnqueueMessage]] = [] var forwardSourcePeerIds = Set() @@ -1962,7 +1963,7 @@ extension ChatControllerImpl { } self.beginDeleteMessagesWithUndo(messageIds: Set(messages.map({ $0.id })), type: .forEveryone) }), - TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}) + TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}) ], actionLayout: .vertical ) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerMediaRecording.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerMediaRecording.swift index ba6084fba9..57ba2caca7 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerMediaRecording.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerMediaRecording.swift @@ -182,7 +182,7 @@ extension ChatControllerImpl { viewOnceAvailable: viewOnceAvailable, inputPanelFrame: (currentInputPanelFrame, self.chatDisplayNode.inputNode != nil), chatNode: self.chatDisplayNode.historyNode, - completion: { [weak self] message, silentPosting, scheduleTime in + completion: { [weak self] message, silentPosting, scheduleTime, repeatPeriod in guard let self, let videoController = self.videoRecorderValue else { return } @@ -230,14 +230,8 @@ extension ChatControllerImpl { }, usedCorrelationId ? correlationId : nil) let messages = [message] - let transformedMessages: [EnqueueMessage] - if let silentPosting { - transformedMessages = self.transformEnqueueMessages(messages, silentPosting: silentPosting) - } else if let scheduleTime { - transformedMessages = self.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime) - } else { - transformedMessages = self.transformEnqueueMessages(messages) - } + let effectiveSilentPosting = silentPosting ?? self.presentationInterfaceState.interfaceState.silentPosting + let transformedMessages = self.transformEnqueueMessages(messages, silentPosting: effectiveSilentPosting, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod) self.sendMessages(transformedMessages) } @@ -758,14 +752,8 @@ extension ChatControllerImpl { let messages: [EnqueueMessage] = [.message(text: "", attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int64(audio.fileSize), attributes: [.Audio(isVoice: true, duration: finalDuration, title: nil, performer: nil, waveform: waveformBuffer)], alternativeRepresentations: [])), threadId: self.chatLocation.threadId, replyToMessageId: self.presentationInterfaceState.interfaceState.replyMessageSubject?.subjectModel, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])] - let transformedMessages: [EnqueueMessage] - if let silentPosting = silentPosting { - transformedMessages = self.transformEnqueueMessages(messages, silentPosting: silentPosting, postpone: postpone) - } else if let scheduleTime = scheduleTime { - transformedMessages = self.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone) - } else { - transformedMessages = self.transformEnqueueMessages(messages) - } + let effectiveSilentPosting = silentPosting ?? self.presentationInterfaceState.interfaceState.silentPosting + let transformedMessages = self.transformEnqueueMessages(messages, silentPosting: effectiveSilentPosting, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone) guard let peerId = self.chatLocation.peerId else { return @@ -783,7 +771,7 @@ extension ChatControllerImpl { guard let videoRecorderValue = self.videoRecorderValue else { return } - videoRecorderValue.sendVideoRecording(silentPosting: silentPosting, scheduleTime: scheduleTime, messageEffect: messageEffect) + videoRecorderValue.sendVideoRecording(silentPosting: silentPosting, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, messageEffect: messageEffect) } } } diff --git a/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift b/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift index acf7b004a7..c508e9bce4 100644 --- a/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift +++ b/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift @@ -94,7 +94,7 @@ func updateChatPresentationInterfaceStateImpl( guard let selfController, value else { return } - selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_Cancel, action: { + selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .genericAction, title: selfController.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_OK, action: { [weak selfController] in guard let selfController else { return @@ -151,7 +151,7 @@ func updateChatPresentationInterfaceStateImpl( case .generic: break case let .inlineBotLocationRequest(peerId): - selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_Cancel, action: { [weak selfController] in + selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .genericAction, title: selfController.presentationData.strings.Common_Cancel, action: { [weak selfController] in guard let selfController else { return } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 90bfead591..0efc6cbbe2 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2387,9 +2387,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }, shouldAnimateMessageTransition ? correlationId : nil) - strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime, repeatPeriod in + strongSelf.presentScheduleTimePicker(completion: { [weak self] result in if let strongSelf = self { - let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone) + let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: result.silentPosting, scheduleTime: result.time, repeatPeriod: result.repeatPeriod, postpone: postpone) strongSelf.sendMessages(transformedMessages) } }) @@ -2557,9 +2557,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G messages = strongSelf.transformEnqueueMessages(messages, silentPosting: true) strongSelf.sendMessages(messages) } else if schedule { - strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime, repeatPeriod in + strongSelf.presentScheduleTimePicker(completion: { [weak self] result in if let strongSelf = self { - let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod) + let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: result.silentPosting, scheduleTime: result.time, repeatPeriod: result.repeatPeriod) strongSelf.sendMessages(transformedMessages) } }) @@ -4031,15 +4031,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard !self.presentAccountFrozenInfoIfNeeded(delay: true) else { return } - self.presentScheduleTimePicker(completion: { [weak self] time, repeatPeriod in + self.presentScheduleTimePicker(completion: { [weak self] result in if let strongSelf = self { if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState { - strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap { + strongSelf.sendMediaRecording(silentPosting: result.silentPosting, scheduleTime: result.time, repeatPeriod: result.repeatPeriod, messageEffect: (params?.effect).flatMap { return ChatSendMessageEffect(id: $0.id) }) } else { - let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting - strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, repeatPeriod: repeatPeriod, messageEffect: (params?.effect).flatMap { + strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: result.silentPosting, scheduleTime: result.time, repeatPeriod: result.repeatPeriod, messageEffect: (params?.effect).flatMap { return ChatSendMessageEffect(id: $0.id) }) { [weak self] in if let strongSelf = self { @@ -4047,7 +4046,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G $0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) } }) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } @@ -8679,9 +8678,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } } else { - self.presentScheduleTimePicker(style: media ? .media : .default, dismissByTapOutside: false, completion: { [weak self] time, repeatPeriod in + self.presentScheduleTimePicker(style: media ? .media : .default, dismissByTapOutside: false, completion: { [weak self] result in if let strongSelf = self { - strongSelf.sendMessages(strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: time, repeatPeriod: repeatPeriod, postpone: postpone), commit: true) + strongSelf.sendMessages(strongSelf.transformEnqueueMessages(messages, silentPosting: result.silentPosting, scheduleTime: result.time, repeatPeriod: result.repeatPeriod, postpone: postpone), commit: true) } }) } @@ -8941,7 +8940,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) } - func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, resetTextInputState: Bool = true, postpone: Bool = false) { + func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, scheduleTime: Int32? = nil, resetTextInputState: Bool = true, postpone: Bool = false) { if !canSendMessagesToChat(self.presentationInterfaceState) { return } @@ -8955,7 +8954,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G isScheduledMessages = true } - let sendMessage: (Int32?) -> Void = { [weak self] scheduleTime in + let sendMessage: (Int32?, Bool) -> Void = { [weak self] scheduleTime, silentPosting in guard let self else { return } @@ -8991,12 +8990,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - if isScheduledMessages { - self.presentScheduleTimePicker(style: .default, dismissByTapOutside: false, completion: { time, repeatPeriod in - sendMessage(time) + if let scheduleTime { + sendMessage(scheduleTime, silentPosting) + } else if isScheduledMessages { + self.presentScheduleTimePicker(style: .default, dismissByTapOutside: false, completion: { result in + sendMessage(result.time, result.silentPosting) }) } else { - sendMessage(nil) + sendMessage(nil, silentPosting) } } @@ -10249,6 +10250,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func presentScheduleTimePicker(style: ChatScheduleTimeControllerStyle = .default, selectedTime: Int32? = nil, selectedRepeatPeriod: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32, Int32?) -> Void) { + self.presentScheduleTimePicker(style: style, selectedTime: selectedTime, selectedRepeatPeriod: selectedRepeatPeriod, dismissByTapOutside: dismissByTapOutside, completion: { result in + completion(result.time, result.repeatPeriod) + }) + } + + func presentScheduleTimePicker(style: ChatScheduleTimeControllerStyle = .default, selectedTime: Int32? = nil, selectedRepeatPeriod: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (ChatScheduleTimeScreen.Result) -> Void) { guard let peerId = self.chatLocation.peerId else { return } @@ -10279,9 +10286,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G currentTime: selectedTime, currentRepeatPeriod: selectedRepeatPeriod, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, + silentPosting: strongSelf.presentationInterfaceState.interfaceState.silentPosting, isDark: style == .media, completion: { result in - completion(result.time, result.repeatPeriod) + completion(result) } ) strongSelf.chatDisplayNode.dismissInput() diff --git a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift index 3e43210c9a..81df672615 100644 --- a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift +++ b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift @@ -21,7 +21,7 @@ fileprivate struct InitialBannedRights { } extension ChatControllerImpl { - fileprivate func applyAdminUserActionsResult(messageIds: Set, result: AdminUserActionsSheet.ChatResult, initialUserBannedRights: [EnginePeer.Id: InitialBannedRights]) { + fileprivate func applyAdminUserActionsResult(messageIds: Set, reactionPeerId: EnginePeer.Id? = nil, result: AdminUserActionsSheet.ChatResult, initialUserBannedRights: [EnginePeer.Id: InitialBannedRights]) { guard let messagesPeerId = self.chatLocation.peerId else { return } @@ -30,7 +30,12 @@ extension ChatControllerImpl { } - var title: String? = messageIds.count == 1 ? self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTitleSingle : self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTitleMultiple + var title: String? + if let _ = reactionPeerId { + title = self.presentationData.strings.Chat_AdminAction_ToastReactionsDeletedTitleSingle + } else { + title = messageIds.count == 1 ? self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTitleSingle : self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTitleMultiple + } if !result.deleteAllFromPeers.isEmpty { title = self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTitleMultiple } @@ -74,6 +79,10 @@ extension ChatControllerImpl { let _ = self.context.engine.messages.clearAuthorHistory(peerId: messagesPeerId, memberId: authorId).startStandalone() } + for authorId in result.deleteAllReactionsFromPeers { + let _ = self.context.engine.messages.deleteAllReactionsWithAuthor(peerId: messagesPeerId, authorId: authorId).startStandalone() + } + for authorId in result.reportSpamPeers { let _ = self.context.engine.peers.reportPeer(peerId: authorId, reason: .spam, message: "").startStandalone() } @@ -88,9 +97,17 @@ extension ChatControllerImpl { } if text.isEmpty { - text = messageIds.count == 1 ? self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTextSingle : self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTextMultiple - if !result.deleteAllFromPeers.isEmpty { + if let _ = reactionPeerId { + text = self.presentationData.strings.Chat_AdminAction_ToastReactionsDeletedTextSingle + } else { + text = messageIds.count == 1 ? self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTextSingle : self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTextMultiple + } + if !result.deleteAllFromPeers.isEmpty && !result.deleteAllReactionsFromPeers.isEmpty { + text = self.presentationData.strings.Chat_AdminAction_ToastMessagesAndReactionsDeletedText + } else if !result.deleteAllFromPeers.isEmpty { text = self.presentationData.strings.Chat_AdminAction_ToastMessagesDeletedTextMultiple + } else if !result.deleteAllReactionsFromPeers.isEmpty { + text = self.presentationData.strings.Chat_AdminAction_ToastReactionsDeletedTextMultiple } title = nil } @@ -332,7 +349,7 @@ extension ChatControllerImpl { guard let self else { return } - self.applyAdminUserActionsResult(messageIds: messageIds, result: result, initialUserBannedRights: initialUserBannedRights) + self.applyAdminUserActionsResult(messageIds: messageIds, reactionPeerId: authorPeer.id, result: result, initialUserBannedRights: initialUserBannedRights) }) } else { mode = .chat( @@ -428,7 +445,7 @@ extension ChatControllerImpl { } self.beginDeleteMessagesWithUndo(messageIds: messageIds, type: .forEveryone) }), - TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}) + TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}) ], actionLayout: .vertical, parseMarkdown: true @@ -490,7 +507,7 @@ extension ChatControllerImpl { } self.beginDeleteMessagesWithUndo(messageIds: messageIds, type: .forEveryone) }), - TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}) + TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}) ], actionLayout: .vertical, parseMarkdown: true @@ -568,7 +585,7 @@ extension ChatControllerImpl { let dateString = stringForDate(timestamp: giveaway.untilDate, timeZone: .current, strings: strongSelf.presentationData.strings) strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: strongSelf.presentationData.strings.Chat_Giveaway_DeleteConfirmation_Title, text: strongSelf.presentationData.strings.Chat_Giveaway_DeleteConfirmation_Text(dateString).string, actions: [TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.Common_Delete, action: { commit() - }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { + }), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { })], parseMarkdown: true), in: .window(.root)) } f(.default) diff --git a/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift b/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift index 6913d4cbb1..71c92156fb 100644 --- a/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift +++ b/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift @@ -317,14 +317,14 @@ extension ChatControllerImpl { let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: true) commit(transformedMessages) case .schedule: - strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime, repeatPeriod in + strongSelf.presentScheduleTimePicker(completion: { [weak self] timeResult in if let strongSelf = self { - let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod) + let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: timeResult.silentPosting, scheduleTime: timeResult.time, repeatPeriod: timeResult.repeatPeriod) commit(transformedMessages) } }) case .whenOnline: - let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleWhenOnlineTimestamp) + let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: strongSelf.presentationInterfaceState.interfaceState.silentPosting, scheduleTime: scheduleWhenOnlineTimestamp) commit(transformedMessages) } } diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift index cca4be7df8..f3bb5fba6b 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift @@ -528,7 +528,9 @@ extension ChatControllerImpl { let contactsController = ContactSelectionControllerImpl(ContactSelectionControllerParams(context: strongSelf.context, style: .glass, updatedPresentationData: strongSelf.updatedPresentationData, title: { $0.Contacts_Title }, displayDeviceContacts: true, multipleSelection: .always, requirePhoneNumbers: true)) contactsController.presentScheduleTimePicker = { [weak self] completion in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(completion: completion) + strongSelf.presentScheduleTimePicker(completion: { result in + completion(result.time, result.repeatPeriod, result.silentPosting) + }) } } contactsController.navigationPresentation = .modal @@ -1057,10 +1059,10 @@ extension ChatControllerImpl { } }, presentSchedulePicker: { [weak self] _, done in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] time, repeatPeriod in + strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] result in if let strongSelf = self { - done(time) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } @@ -1114,10 +1116,10 @@ extension ChatControllerImpl { })], actionLayout: .vertical), in: .window(.root)) }, presentSchedulePicker: { [weak self] _, done in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] time, repeatPeriod in + strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] result in if let strongSelf = self { - done(time) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } @@ -1367,10 +1369,10 @@ extension ChatControllerImpl { } controller.presentSchedulePicker = { [weak self] media, done in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(style: media ? .media : .default, completion: { [weak self] time, repeatPeriod in + strongSelf.presentScheduleTimePicker(style: media ? .media : .default, completion: { [weak self] result in if let strongSelf = self { - done(time) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } @@ -1495,20 +1497,20 @@ extension ChatControllerImpl { configureLegacyAssetPicker(controller, context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, presentWebSearch: editingMedia ? nil : { [weak self, weak legacyController] in if let strongSelf = self { - let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: searchBotsConfiguration, mode: .media(attachment: false, completion: { results, selectionState, editingState, silentPosting in + let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: searchBotsConfiguration, mode: .media(attachment: false, completion: { results, selectionState, editingState, silentPosting, scheduleTime in if let legacyController = legacyController { legacyController.dismiss() } legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { result in if let strongSelf = self { - strongSelf.enqueueChatContextResult(results, result, hideVia: true) + strongSelf.enqueueChatContextResult(results, result, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime) } }, enqueueMediaMessages: { signals in if let strongSelf = self { if editingMedia { strongSelf.editMessageMediaWithLegacySignals(signals) } else { - strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting) + strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime) } } }) @@ -1533,10 +1535,10 @@ extension ChatControllerImpl { strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }, presentSchedulePicker: { [weak self] media, done in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(style: media ? .media : .default, completion: { [weak self] time, repeatPeriod in + strongSelf.presentScheduleTimePicker(style: media ? .media : .default, completion: { [weak self] result in if let strongSelf = self { - done(time) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } @@ -1578,18 +1580,18 @@ extension ChatControllerImpl { let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots()) |> deliverOnMainQueue).startStandalone(next: { [weak self] configuration in if let strongSelf = self { - let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: configuration, mode: .media(attachment: attachment, completion: { [weak self] results, selectionState, editingState, silentPosting in + let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: configuration, mode: .media(attachment: attachment, completion: { [weak self] results, selectionState, editingState, silentPosting, scheduleTime in self?.attachmentController?.dismiss(animated: true, completion: nil) legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { [weak self] result in if let strongSelf = self { - strongSelf.enqueueChatContextResult(results, result, hideVia: true) + strongSelf.enqueueChatContextResult(results, result, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime) } }, enqueueMediaMessages: { [weak self] signals in if let strongSelf = self, !signals.isEmpty { if editingMessage { strongSelf.editMessageMediaWithLegacySignals(signals) } else { - strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting) + strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime) } } }) @@ -1967,10 +1969,10 @@ extension ChatControllerImpl { } }, presentSchedulePicker: { [weak self] _, done in if let strongSelf = self { - strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] time, repeatPeriod in + strongSelf.presentScheduleTimePicker(style: .media, completion: { [weak self] result in if let strongSelf = self { - done(time) - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + done(result.time, result.silentPosting) + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && result.time != scheduleWhenOnlineTimestamp { strongSelf.openScheduledMessages() } } diff --git a/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift b/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift index 0944f199b8..66ccd16977 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift @@ -27,6 +27,17 @@ private func inputQueryResultPriority(_ result: ChatPresentationInputQueryResult } } +private func hasBannedInlineContent(chatPresentationInterfaceState: ChatPresentationInterfaceState) -> Bool { + if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel { + let canBypass = canBypassRestrictions(chatPresentationInterfaceState: chatPresentationInterfaceState) + return channel.hasBannedPermission(.banSendInline, ignoreDefault: canBypass) != nil + } else if let group = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup { + return group.hasBannedPermission(.banSendInline) + } else { + return false + } +} + func textInputContextPanel(context: AccountContext, chatPresentationInterfaceState: ChatPresentationInterfaceState, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, currentPanel: ChatInputContextPanelNode?) -> ChatInputContextPanelNode? { guard let controllerInteraction else { return nil @@ -45,15 +56,8 @@ func textInputContextPanel(context: AccountContext, chatPresentationInterfaceSta }).first else { return nil } - - var hasBannedInlineContent = false - if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.hasBannedPermission(.banSendInline) != nil { - hasBannedInlineContent = true - } else if let group = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup, group.hasBannedPermission(.banSendInline) { - hasBannedInlineContent = true - } - - if hasBannedInlineContent { + + if hasBannedInlineContent(chatPresentationInterfaceState: chatPresentationInterfaceState) { switch inputQueryResult { case .stickers, .contextRequestResult: if let currentPanel = currentPanel as? DisabledContextResultsChatInputContextPanelNode { @@ -183,15 +187,8 @@ func inputContextPanelForChatPresentationIntefaceState(_ chatPresentationInterfa }).first else { return nil } - - var hasBannedInlineContent = false - if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.hasBannedPermission(.banSendInline) != nil { - hasBannedInlineContent = true - } else if let group = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup, group.hasBannedPermission(.banSendInline) { - hasBannedInlineContent = true - } - - if hasBannedInlineContent { + + if hasBannedInlineContent(chatPresentationInterfaceState: chatPresentationInterfaceState) { switch inputQueryResult { case .stickers, .contextRequestResult: if let currentPanel = currentPanel as? DisabledContextResultsChatInputContextPanelNode { @@ -305,4 +302,3 @@ func chatOverlayContextPanelForChatPresentationIntefaceState(_ chatPresentationI return nil } - diff --git a/submodules/TelegramUI/Sources/ContactSelectionController.swift b/submodules/TelegramUI/Sources/ContactSelectionController.swift index 047253a186..531c915b52 100644 --- a/submodules/TelegramUI/Sources/ContactSelectionController.swift +++ b/submodules/TelegramUI/Sources/ContactSelectionController.swift @@ -70,7 +70,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController private let isPeerEnabled: (ContactListPeer) -> Bool var dismissed: (() -> Void)? - var presentScheduleTimePicker: (@escaping (Int32, Int32?) -> Void) -> Void = { _ in } + var presentScheduleTimePicker: (@escaping (Int32, Int32?, Bool) -> Void) -> Void = { _ in } private let createActionDisposable = MetaDisposable() private let confirmationDisposable = MetaDisposable() @@ -646,8 +646,8 @@ final class ContactsPickerContext: AttachmentMediaPickerContext { } func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) { - self.controller?.presentScheduleTimePicker ({ time, repeatPeriod in - self.controller?.contactsNode.requestMultipleAction?(false, time, parameters) + self.controller?.presentScheduleTimePicker ({ time, repeatPeriod, silentPosting in + self.controller?.contactsNode.requestMultipleAction?(silentPosting, time, parameters) }) } diff --git a/submodules/TelegramUI/Sources/CreateChannelController.swift b/submodules/TelegramUI/Sources/CreateChannelController.swift index 1aac1f9485..eddc7f5297 100644 --- a/submodules/TelegramUI/Sources/CreateChannelController.swift +++ b/submodules/TelegramUI/Sources/CreateChannelController.swift @@ -19,8 +19,12 @@ import PeerInfoUI import MapResourceToAvatarSizes import LegacyMediaPickerUI import TextFormat +import MediaEditor +import MediaEditorScreen +import CameraScreen import AvatarEditorScreen import OldChannelsController +import Photos import AVFoundation private struct CreateChannelArguments { @@ -363,10 +367,29 @@ public func createChannelController(context: AccountContext, mode: CreateChannel let actionsDisposable = DisposableSet() - let currentAvatarMixin = Atomic(value: nil) - - let uploadedAvatar = Promise() - var uploadedVideoAvatar: (Promise, Double?)? = nil + var avatarPickerHolder: Any? + var pendingAvatar: CreatePendingPeerAvatar? + let applyPendingAvatar: (CreatePendingPeerAvatar) -> Void = { avatar in + pendingAvatar = avatar + updateState { current in + var current = current + current.avatar = avatar.updatingAvatar + return current + } + } + let updatePendingAvatarIfCurrent: (CreatePendingPeerAvatar) -> Void = { avatar in + if pendingAvatar?.previewRepresentation.resource.id == avatar.previewRepresentation.resource.id { + applyPendingAvatar(avatar) + } + } + let clearPendingAvatar: () -> Void = { + pendingAvatar = nil + updateState { current in + var current = current + current.avatar = nil + return current + } + } let checkAddressNameDisposable = MetaDisposable() actionsDisposable.add(checkAddressNameDisposable) @@ -434,11 +457,8 @@ public func createChannelController(context: AccountContext, mode: CreateChannel } } }).start(next: { peerId in - let updatingAvatar = stateValue.with { - return $0.avatar - } - if let _ = updatingAvatar { - let _ = context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in + if let pendingAvatar { + let _ = context.engine.peers.updatePeerPhoto(peerId: peerId, photo: pendingAvatar.uploadedPhoto, video: pendingAvatar.uploadedVideo, videoStartTimestamp: pendingAvatar.videoStartTimestamp, markup: pendingAvatar.markup, mapResourceToAvatarSizes: { resource, representations in return mapResourceToAvatarSizes(engine: context.engine, resource: resource, representations: representations) }).start() } @@ -474,216 +494,127 @@ public func createChannelController(context: AccountContext, mode: CreateChannel }, changeProfilePhoto: { endEditingImpl?() - let title = stateValue.with { state -> String in - return state.editingName.composedTitle - } + let keyboardInputData = Promise() + keyboardInputData.set(AvatarEditorScreen.inputData(context: context, isGroup: true)) - let _ = (context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId), - TelegramEngine.EngineData.Item.Configuration.SearchBots() - ) - |> deliverOnMainQueue).start(next: { peer, searchBotsConfiguration in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } + var dismissPickerImpl: (() -> Void)? + let (mainController, pickerHolder) = context.sharedContext.makeAvatarMediaPickerScreen(context: context, getSourceRect: { return nil }, canDelete: pendingAvatar != nil, performDelete: { + clearPendingAvatar() + }, completion: { result, transitionView, transitionRect, transitionImage, fromCamera, _, cancelled in + avatarPickerHolder = nil - let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme) - legacyController.statusBar.statusBarStyle = .Ignore - - let emptyController = LegacyEmptyController(context: legacyController.context)! - let navigationController = makeLegacyNavigationController(rootController: emptyController) - navigationController.setNavigationBarHidden(true, animated: false) - navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) - - legacyController.bind(controller: navigationController) - - endEditingImpl?() - presentControllerImpl?(legacyController, nil) - - let completedChannelPhotoImpl: (UIImage) -> Void = { image in - if let data = image.jpegData(compressionQuality: 0.6) { - let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(resource.id), data: data) - let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) - uploadedAvatar.set(context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(resource))) - uploadedVideoAvatar = nil - updateState { current in - var current = current - current.avatar = .image(representation, false) - return current - } + let applyPhoto: (UIImage) -> Void = { image in + if let avatar = CreatePeerAvatarSetup.photo(context: context, image: image) { + applyPendingAvatar(avatar) + } + } + let applyVideo: (UIImage, MediaEditorScreenImpl.MediaResult.VideoResult?, MediaEditorValues?, UploadPeerPhotoMarkup?) -> Void = { image, video, values, markup in + if let avatar = CreatePeerAvatarSetup.video(context: context, image: image, video: video, values: values, markup: markup, didCompleteLoadingPreview: { avatar in + updatePendingAvatarIfCurrent(avatar) + }) { + applyPendingAvatar(avatar) } } - let completedChannelVideoImpl: (UIImage, Any?, TGVideoEditAdjustments?) -> Void = { image, asset, adjustments in - if let data = image.jpegData(compressionQuality: 0.6) { - let photoResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(photoResource.id), data: data) - let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) - updateState { state in - var state = state - state.avatar = .image(representation, true) - return state + let subject: Signal + if let asset = result as? PHAsset { + subject = .single(.asset(asset)) + } else if let image = result as? UIImage { + subject = .single(.image(image: image, dimensions: PixelDimensions(image.size), additionalImage: nil, additionalImagePosition: .bottomRight, fromCamera: false)) + } else if let result = result as? Signal { + subject = result + |> map { value -> MediaEditorScreenImpl.Subject? in + switch value { + case .pendingImage: + return nil + case let .image(image): + return .image(image: image.image, dimensions: PixelDimensions(image.image.size), additionalImage: nil, additionalImagePosition: .topLeft, fromCamera: false) + case let .video(video): + return .video(videoPath: video.videoPath, thumbnail: video.coverImage, mirror: video.mirror, additionalVideoPath: nil, additionalThumbnail: nil, dimensions: video.dimensions, duration: video.duration, videoPositionChanges: [], additionalVideoPosition: .topLeft, fromCamera: false) + default: + return nil } - - var videoStartTimestamp: Double? = nil - if let adjustments = adjustments, adjustments.videoStartValue > 0.0 { - videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue - } - - let signal = Signal { subscriber in - let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in - if let paintingData = adjustments.paintingData, paintingData.hasAnimation { - return LegacyPaintEntityRenderer(postbox: context.account.postbox, adjustments: adjustments) - } else { - return nil - } - } - - let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4") - let uploadInterface = LegacyLiveUploadInterface(context: context) - let signal: SSignal - if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer { - let durationSignal: SSignal = SSignal(generator: { subscriber in - let disposable = (entityRenderer.duration()).start(next: { duration in - subscriber.putNext(duration) - subscriber.putCompletion() - }) - - return SBlockDisposable(block: { - disposable.dispose() - }) - }) - signal = durationSignal.map(toSignal: { duration -> SSignal in - if let duration = duration as? Double { - return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, path: tempFile.path, watcher: nil, entityRenderer: entityRenderer)! - } else { - return SSignal.single(nil) - } - }) - - } else if let asset = asset as? AVAsset { - signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, path: tempFile.path, watcher: uploadInterface, entityRenderer: entityRenderer)! - } else { - signal = SSignal.complete() - } - - let signalDisposable = signal.start(next: { next in - if let result = next as? TGMediaVideoConversionResult { - if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) { - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(photoResource.id), data: data) - } - - if let timestamp = videoStartTimestamp { - videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05)) - } - - var value = stat() - if stat(result.fileURL.path, &value) == 0 { - if let data = try? Data(contentsOf: result.fileURL) { - let resource: TelegramMediaResource - if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult { - resource = LocalFileMediaResource(fileId: liveUploadData.id) - } else { - resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - } - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(resource.id), data: data, synchronous: true) - subscriber.putNext(resource) - - EngineTempBox.shared.dispose(tempFile) - } - } - subscriber.putCompletion() - } - }, error: { _ in - }, completed: nil) - - let disposable = ActionDisposable { - signalDisposable?.dispose() - } - - return ActionDisposable { - disposable.dispose() - } - } - - uploadedAvatar.set(context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(photoResource))) - - let promise = Promise() - promise.set(signal - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { resource -> Signal in - if let resource = resource { - return context.engine.peers.uploadedPeerVideo(resource: EngineMediaResource(resource)) |> map(Optional.init) - } else { - return .single(nil) - } - } |> afterNext { next in - if let next = next, next.isCompleted { - updateState { state in - var state = state - state.avatar = .image(representation, false) - return state - } - } - }) - uploadedVideoAvatar = (promise, videoStartTimestamp) } + } else { + let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .channel, markup: nil) + controller.imageCompletion = { image, commit in + applyPhoto(image) + commit() + } + controller.videoCompletion = { image, _, _, markup, commit in + applyVideo(image, nil, nil, markup) + commit() + } + pushControllerImpl?(controller) + return } - let keyboardInputData = Promise() - keyboardInputData.set(AvatarEditorScreen.inputData(context: context, isGroup: true)) - - let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)! - mixin.stickersContext = LegacyPaintStickersContext(context: context) - let _ = currentAvatarMixin.swap(mixin) - mixin.requestSearchController = { assetsController in - let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in - assetsController?.dismiss() - completedChannelPhotoImpl(result) - })) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } -// mixin.requestAvatarEditor = { imageCompletion, videoCompletion in -// guard let imageCompletion, let videoCompletion else { -// return -// } -// let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .channel, markup: nil) -// controller.imageCompletion = imageCompletion -// controller.videoCompletion = videoCompletion -// pushControllerImpl?(controller) -// } - mixin.didFinishWithImage = { image in - if let image = image { - completedChannelPhotoImpl(image) - } - } - mixin.didFinishWithVideo = { image, asset, adjustments in - if let image = image, let asset = asset { - completedChannelVideoImpl(image, asset, adjustments) - } - } - if stateValue.with({ $0.avatar }) != nil { - mixin.didFinishWithDelete = { - updateState { current in - var current = current - current.avatar = nil - return current + let editorController = MediaEditorScreenImpl( + context: context, + mode: .avatarEditor, + subject: subject, + transitionIn: fromCamera ? .camera : transitionView.flatMap({ .gallery( + MediaEditorScreenImpl.TransitionIn.GalleryTransitionIn( + sourceView: $0, + sourceRect: transitionRect, + sourceImage: transitionImage + ) + ) }), + transitionOut: { finished, _ in + if !finished, let transitionView { + return MediaEditorScreenImpl.TransitionOut( + destinationView: transitionView, + destinationRect: transitionView.bounds, + destinationCornerRadius: 0.0 + ) } - uploadedAvatar.set(.never()) - } - } - mixin.didDismiss = { [weak legacyController] in - let _ = currentAvatarMixin.swap(nil) - legacyController?.dismiss() - } - let menuController = mixin.present() - if let menuController = menuController { - menuController.customRemoveFromParentViewController = { [weak legacyController] in - legacyController?.dismiss() - } + return nil + }, + completion: { results, commit in + guard let result = results.first else { + return + } + switch result.media { + case let .image(image, _): + applyPhoto(image) + commit({}) + case let .video(video, coverImage, values, _, _): + if let coverImage { + applyVideo(coverImage, video, values, nil) + } + commit({}) + default: + break + } + dismissPickerImpl?() + } as ([MediaEditorScreenImpl.Result], @escaping (@escaping () -> Void) -> Void) -> Void + ) + editorController.cancelled = { _ in + cancelled() } + pushControllerImpl?(editorController) + }, dismissed: { + avatarPickerHolder = nil }) + avatarPickerHolder = pickerHolder + if let mainController { + dismissPickerImpl = { [weak mainController] in + if let mainController, let navigationController = mainController.navigationController { + var viewControllers = navigationController.viewControllers + viewControllers = viewControllers.filter { controller in + return !(controller is CameraScreen) && controller !== mainController + } + navigationController.setViewControllers(viewControllers, animated: false) + } + } + if mainController is ActionSheetController { + presentControllerImpl?(mainController, nil) + } else { + mainController.navigationPresentation = .flatModal + mainController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) + pushControllerImpl?(mainController) + } + } }, focusOnDescription: { focusOnDescriptionImpl?() }, updatePublicLinkText: { text in @@ -741,6 +672,8 @@ public func createChannelController(context: AccountContext, mode: CreateChannel return (controllerState, (listState, arguments)) } |> afterDisposed { actionsDisposable.dispose() + + let _ = avatarPickerHolder } let controller = ItemListController(context: context, state: signal) diff --git a/submodules/TelegramUI/Sources/CreateGroupController.swift b/submodules/TelegramUI/Sources/CreateGroupController.swift index ce7fbe0ccb..f0ce6b6cc2 100644 --- a/submodules/TelegramUI/Sources/CreateGroupController.swift +++ b/submodules/TelegramUI/Sources/CreateGroupController.swift @@ -34,6 +34,10 @@ import TextFormat import AvatarEditorScreen import SendInviteLinkScreen import OldChannelsController +import MediaEditor +import MediaEditorScreen +import CameraScreen +import Photos import AVFoundation private struct CreateGroupArguments { @@ -563,10 +567,29 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] let checkAddressNameDisposable = MetaDisposable() actionsDisposable.add(checkAddressNameDisposable) - let currentAvatarMixin = Atomic(value: nil) - - let uploadedAvatar = Promise() - var uploadedVideoAvatar: (Promise, Double?)? = nil + var avatarPickerHolder: Any? + var pendingAvatar: CreatePendingPeerAvatar? + let applyPendingAvatar: (CreatePendingPeerAvatar) -> Void = { avatar in + pendingAvatar = avatar + updateState { current in + var current = current + current.avatar = avatar.updatingAvatar + return current + } + } + let updatePendingAvatarIfCurrent: (CreatePendingPeerAvatar) -> Void = { avatar in + if pendingAvatar?.previewRepresentation.resource.id == avatar.previewRepresentation.resource.id { + applyPendingAvatar(avatar) + } + } + let clearPendingAvatar: () -> Void = { + pendingAvatar = nil + updateState { current in + var current = current + current.avatar = nil + return current + } + } if initialTitle == nil && peerIds.count > 0 && peerIds.count < 5 { let _ = (context.engine.data.get( @@ -793,18 +816,14 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] let _ = createSignal let _ = replaceControllerImpl let _ = dismissImpl - let _ = uploadedVideoAvatar actionsDisposable.add((createSignal |> mapToSignal { result -> Signal in guard let result = result else { return .single(nil) } - let updatingAvatar = stateValue.with { - return $0.avatar - } - if let _ = updatingAvatar { - return context.engine.peers.updatePeerPhoto(peerId: result.peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in + if let pendingAvatar { + return context.engine.peers.updatePeerPhoto(peerId: result.peerId, photo: pendingAvatar.uploadedPhoto, video: pendingAvatar.uploadedVideo, videoStartTimestamp: pendingAvatar.videoStartTimestamp, markup: pendingAvatar.markup, mapResourceToAvatarSizes: { resource, representations in return mapResourceToAvatarSizes(engine: context.engine, resource: resource, representations: representations) }) |> ignoreValues @@ -893,216 +912,134 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] }, changeProfilePhoto: { endEditingImpl?() - let title = stateValue.with { state -> String in - return state.editingName.composedTitle + let peerType: AvatarEditorScreen.PeerType + if case let .requestPeer(group) = mode, group.isForum == true { + peerType = .forum + } else { + peerType = .group } - let _ = (context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId), - TelegramEngine.EngineData.Item.Configuration.SearchBots() - ) - |> deliverOnMainQueue).start(next: { peer, searchBotsConfiguration in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let keyboardInputData = Promise() + keyboardInputData.set(AvatarEditorScreen.inputData(context: context, isGroup: true)) + + var dismissPickerImpl: (() -> Void)? + let (mainController, pickerHolder) = context.sharedContext.makeAvatarMediaPickerScreen(context: context, getSourceRect: { return nil }, canDelete: pendingAvatar != nil, performDelete: { + clearPendingAvatar() + }, completion: { result, transitionView, transitionRect, transitionImage, fromCamera, _, cancelled in + avatarPickerHolder = nil - let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme) - legacyController.statusBar.statusBarStyle = .Ignore - - let emptyController = LegacyEmptyController(context: legacyController.context)! - let navigationController = makeLegacyNavigationController(rootController: emptyController) - navigationController.setNavigationBarHidden(true, animated: false) - navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) - - legacyController.bind(controller: navigationController) - - endEditingImpl?() - presentControllerImpl?(legacyController, nil) - - let completedGroupPhotoImpl: (UIImage) -> Void = { image in - if let data = image.jpegData(compressionQuality: 0.6) { - let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(resource.id), data: data) - let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) - uploadedAvatar.set(context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(resource))) - uploadedVideoAvatar = nil - updateState { current in - var current = current - current.avatar = .image(representation, false) - return current - } + let applyPhoto: (UIImage) -> Void = { image in + if let avatar = CreatePeerAvatarSetup.photo(context: context, image: image) { + applyPendingAvatar(avatar) + } + } + let applyVideo: (UIImage, MediaEditorScreenImpl.MediaResult.VideoResult?, MediaEditorValues?, UploadPeerPhotoMarkup?) -> Void = { image, video, values, markup in + if let avatar = CreatePeerAvatarSetup.video(context: context, image: image, video: video, values: values, markup: markup, didCompleteLoadingPreview: { avatar in + updatePendingAvatarIfCurrent(avatar) + }) { + applyPendingAvatar(avatar) } } - let completedGroupVideoImpl: (UIImage, Any?, TGVideoEditAdjustments?) -> Void = { image, asset, adjustments in - if let data = image.jpegData(compressionQuality: 0.6) { - let photoResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(photoResource.id), data: data) - let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) - updateState { state in - var state = state - state.avatar = .image(representation, true) - return state + let subject: Signal + if let asset = result as? PHAsset { + subject = .single(.asset(asset)) + } else if let image = result as? UIImage { + subject = .single(.image(image: image, dimensions: PixelDimensions(image.size), additionalImage: nil, additionalImagePosition: .bottomRight, fromCamera: false)) + } else if let result = result as? Signal { + subject = result + |> map { value -> MediaEditorScreenImpl.Subject? in + switch value { + case .pendingImage: + return nil + case let .image(image): + return .image(image: image.image, dimensions: PixelDimensions(image.image.size), additionalImage: nil, additionalImagePosition: .topLeft, fromCamera: false) + case let .video(video): + return .video(videoPath: video.videoPath, thumbnail: video.coverImage, mirror: video.mirror, additionalVideoPath: nil, additionalThumbnail: nil, dimensions: video.dimensions, duration: video.duration, videoPositionChanges: [], additionalVideoPosition: .topLeft, fromCamera: false) + default: + return nil } - - var videoStartTimestamp: Double? = nil - if let adjustments = adjustments, adjustments.videoStartValue > 0.0 { - videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue - } - - let signal = Signal { subscriber in - let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in - if let paintingData = adjustments.paintingData, paintingData.hasAnimation { - return LegacyPaintEntityRenderer(postbox: context.account.postbox, adjustments: adjustments) - } else { - return nil - } - } - - let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4") - let uploadInterface = LegacyLiveUploadInterface(context: context) - let signal: SSignal - if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer { - let durationSignal: SSignal = SSignal(generator: { subscriber in - let disposable = (entityRenderer.duration()).start(next: { duration in - subscriber.putNext(duration) - subscriber.putCompletion() - }) - - return SBlockDisposable(block: { - disposable.dispose() - }) - }) - signal = durationSignal.map(toSignal: { duration -> SSignal in - if let duration = duration as? Double { - return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, path: tempFile.path, watcher: nil, entityRenderer: entityRenderer)! - } else { - return SSignal.single(nil) - } - }) - - } else if let asset = asset as? AVAsset { - signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, path: tempFile.path, watcher: uploadInterface, entityRenderer: entityRenderer)! - } else { - signal = SSignal.complete() - } - - let signalDisposable = signal.start(next: { next in - if let result = next as? TGMediaVideoConversionResult { - if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) { - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(photoResource.id), data: data) - } - - if let timestamp = videoStartTimestamp { - videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05)) - } - - var value = stat() - if stat(result.fileURL.path, &value) == 0 { - if let data = try? Data(contentsOf: result.fileURL) { - let resource: TelegramMediaResource - if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult { - resource = LocalFileMediaResource(fileId: liveUploadData.id) - } else { - resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - } - context.engine.resources.storeResourceData(id: EngineMediaResource.Id(resource.id), data: data, synchronous: true) - subscriber.putNext(resource) - - EngineTempBox.shared.dispose(tempFile) - } - } - subscriber.putCompletion() - } - }, error: { _ in - }, completed: nil) - - let disposable = ActionDisposable { - signalDisposable?.dispose() - } - - return ActionDisposable { - disposable.dispose() - } - } - - uploadedAvatar.set(context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(photoResource))) - - let promise = Promise() - promise.set(signal - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { resource -> Signal in - if let resource = resource { - return context.engine.peers.uploadedPeerVideo(resource: EngineMediaResource(resource)) |> map(Optional.init) - } else { - return .single(nil) - } - } |> afterNext { next in - if let next = next, next.isCompleted { - updateState { state in - var state = state - state.avatar = .image(representation, false) - return state - } - } - }) - uploadedVideoAvatar = (promise, videoStartTimestamp) } + } else { + let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: peerType, markup: nil) + controller.imageCompletion = { image, commit in + applyPhoto(image) + commit() + } + controller.videoCompletion = { image, _, _, markup, commit in + applyVideo(image, nil, nil, markup) + commit() + } + pushImpl?(controller) + return } - let keyboardInputData = Promise() - keyboardInputData.set(AvatarEditorScreen.inputData(context: context, isGroup: true)) - - let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)! - mixin.stickersContext = LegacyPaintStickersContext(context: context) - let _ = currentAvatarMixin.swap(mixin) - mixin.requestSearchController = { assetsController in - let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in - assetsController?.dismiss() - completedGroupPhotoImpl(result) - })) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } -// mixin.requestAvatarEditor = { imageCompletion, videoCompletion in -// guard let imageCompletion, let videoCompletion else { -// return -// } -// let controller = AvatarEditorScreen(context: context, inputData: keyboardInputData.get(), peerType: .group, markup: nil) -// controller.imageCompletion = imageCompletion -// controller.videoCompletion = videoCompletion -// pushImpl?(controller) -// } - mixin.didFinishWithImage = { image in - if let image = image { - completedGroupPhotoImpl(image) - } - } - mixin.didFinishWithVideo = { image, asset, adjustments in - if let image = image, let asset = asset { - completedGroupVideoImpl(image, asset, adjustments) - } - } - if stateValue.with({ $0.avatar }) != nil { - mixin.didFinishWithDelete = { - updateState { current in - var current = current - current.avatar = nil - return current + let editorController = MediaEditorScreenImpl( + context: context, + mode: .avatarEditor, + subject: subject, + transitionIn: fromCamera ? .camera : transitionView.flatMap({ .gallery( + MediaEditorScreenImpl.TransitionIn.GalleryTransitionIn( + sourceView: $0, + sourceRect: transitionRect, + sourceImage: transitionImage + ) + ) }), + transitionOut: { finished, _ in + if !finished, let transitionView { + return MediaEditorScreenImpl.TransitionOut( + destinationView: transitionView, + destinationRect: transitionView.bounds, + destinationCornerRadius: 0.0 + ) } - uploadedAvatar.set(.never()) - } - } - mixin.didDismiss = { [weak legacyController] in - let _ = currentAvatarMixin.swap(nil) - legacyController?.dismiss() - } - let menuController = mixin.present() - if let menuController = menuController { - menuController.customRemoveFromParentViewController = { [weak legacyController] in - legacyController?.dismiss() - } + return nil + }, + completion: { results, commit in + guard let result = results.first else { + return + } + switch result.media { + case let .image(image, _): + applyPhoto(image) + commit({}) + case let .video(video, coverImage, values, _, _): + if let coverImage { + applyVideo(coverImage, video, values, nil) + } + commit({}) + default: + break + } + dismissPickerImpl?() + } as ([MediaEditorScreenImpl.Result], @escaping (@escaping () -> Void) -> Void) -> Void + ) + editorController.cancelled = { _ in + cancelled() } + pushImpl?(editorController) + }, dismissed: { + avatarPickerHolder = nil }) + avatarPickerHolder = pickerHolder + if let mainController { + dismissPickerImpl = { [weak mainController] in + if let mainController, let navigationController = mainController.navigationController { + var viewControllers = navigationController.viewControllers + viewControllers = viewControllers.filter { controller in + return !(controller is CameraScreen) && controller !== mainController + } + navigationController.setViewControllers(viewControllers, animated: false) + } + } + if mainController is ActionSheetController { + presentControllerImpl?(mainController, nil) + } else { + mainController.navigationPresentation = .flatModal + mainController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) + pushImpl?(mainController) + } + } }, changeLocation: { endEditingImpl?() @@ -1313,6 +1250,8 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] } |> afterDisposed { actionsDisposable.dispose() + + let _ = avatarPickerHolder } let controller = ItemListController(context: context, state: signal) diff --git a/submodules/TelegramUI/Sources/CreatePeerAvatarSetup.swift b/submodules/TelegramUI/Sources/CreatePeerAvatarSetup.swift new file mode 100644 index 0000000000..603e188909 --- /dev/null +++ b/submodules/TelegramUI/Sources/CreatePeerAvatarSetup.swift @@ -0,0 +1,216 @@ +import Foundation +import UIKit +import SwiftSignalKit +import TelegramCore +import AccountContext +import MediaEditor +import MediaEditorScreen +import ItemListAvatarAndNameInfoItem +import Photos +import AVFoundation + +struct CreatePendingPeerAvatar { + let previewRepresentation: TelegramMediaImageRepresentation + let isLoadingPreview: Bool + let uploadedPhoto: Signal + let uploadedVideo: Signal? + let videoStartTimestamp: Double? + let markup: UploadPeerPhotoMarkup? + + var updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar { + return .image(self.previewRepresentation, self.isLoadingPreview) + } +} + +enum CreatePeerAvatarSetup { + private static func makePhotoRepresentation(context: AccountContext, image: UIImage) -> (LocalFileMediaResource, TelegramMediaImageRepresentation)? { + guard let data = image.jpegData(compressionQuality: 0.6) else { + return nil + } + + let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) + context.engine.resources.storeResourceData(id: EngineMediaResource.Id(resource.id), data: data) + let representation = TelegramMediaImageRepresentation( + dimensions: PixelDimensions(width: 640, height: 640), + resource: resource, + progressiveSizes: [], + immediateThumbnailData: nil, + hasVideo: false, + isPersonal: false + ) + return (resource, representation) + } + + static func photo(context: AccountContext, image: UIImage) -> CreatePendingPeerAvatar? { + guard let (resource, representation) = self.makePhotoRepresentation(context: context, image: image) else { + return nil + } + + return CreatePendingPeerAvatar( + previewRepresentation: representation, + isLoadingPreview: false, + uploadedPhoto: context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(resource)), + uploadedVideo: nil, + videoStartTimestamp: nil, + markup: nil + ) + } + + static func video( + context: AccountContext, + image: UIImage, + video: MediaEditorScreenImpl.MediaResult.VideoResult?, + values: MediaEditorValues?, + markup: UploadPeerPhotoMarkup?, + didCompleteLoadingPreview: @escaping (CreatePendingPeerAvatar) -> Void = { _ in } + ) -> CreatePendingPeerAvatar? { + var shouldUploadVideo = true + if markup != nil { + if let data = context.currentAppConfiguration.with({ $0 }).data, let uploadVideoValue = data["upload_markup_video"] as? Bool, uploadVideoValue { + shouldUploadVideo = true + } else { + shouldUploadVideo = false + } + } + + guard let (photoResource, representation) = self.makePhotoRepresentation(context: context, image: image) else { + return nil + } + + let uploadedPhoto = context.engine.peers.uploadedPeerPhoto(resource: EngineMediaResource(photoResource)) + + var videoStartTimestamp: Double? = nil + if let values, let coverImageTimestamp = values.coverImageTimestamp, coverImageTimestamp > 0.0 { + videoStartTimestamp = coverImageTimestamp - (values.videoTrimRange?.lowerBound ?? 0.0) + } + + let hasVideoUpload = shouldUploadVideo && video != nil && values != nil + guard hasVideoUpload, let video, let values else { + return CreatePendingPeerAvatar( + previewRepresentation: representation, + isLoadingPreview: false, + uploadedPhoto: uploadedPhoto, + uploadedVideo: nil, + videoStartTimestamp: videoStartTimestamp, + markup: markup + ) + } + + let account = context.account + let videoResource: Signal + + var exportSubject: Signal<(MediaEditorVideoExport.Subject, Double), NoError>? + switch video { + case let .imageFile(path): + if let image = UIImage(contentsOfFile: path) { + exportSubject = .single((.image(image: image), 3.0)) + } + case let .videoFile(path): + let asset = AVURLAsset(url: NSURL(fileURLWithPath: path) as URL) + exportSubject = .single((.video(asset: asset, isStory: false), asset.duration.seconds)) + case let .asset(localIdentifier): + exportSubject = Signal { subscriber in + let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil) + if fetchResult.count != 0 { + let asset = fetchResult.object(at: 0) + if asset.mediaType == .video { + PHImageManager.default().requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in + if let avAsset { + subscriber.putNext((.video(asset: avAsset, isStory: true), avAsset.duration.seconds)) + subscriber.putCompletion() + } + } + } else { + let options = PHImageRequestOptions() + options.deliveryMode = .highQualityFormat + PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: options) { image, _ in + if let image { + subscriber.putNext((.image(image: image), 3.0)) + subscriber.putCompletion() + } + } + } + } + return EmptyDisposable + } + } + + guard let exportSubject else { + return CreatePendingPeerAvatar( + previewRepresentation: representation, + isLoadingPreview: false, + uploadedPhoto: uploadedPhoto, + uploadedVideo: nil, + videoStartTimestamp: videoStartTimestamp, + markup: markup + ) + } + + videoResource = exportSubject + |> castError(UploadPeerPhotoError.self) + |> mapToSignal { exportSubject, duration in + return Signal { subscriber in + let configuration = recommendedVideoExportConfiguration(values: values, duration: duration, forceFullHd: true, frameRate: 60.0, isAvatar: true) + let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4") + let videoExport = MediaEditorVideoExport(postbox: context.account.postbox, subject: exportSubject, configuration: configuration, outputPath: tempFile.path, textScale: 2.0) + let _ = (videoExport.status + |> deliverOnMainQueue).startStandalone(next: { status in + switch status { + case .completed: + if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path), options: .mappedIfSafe) { + let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) + account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) + subscriber.putNext(resource) + subscriber.putCompletion() + } + EngineTempBox.shared.dispose(tempFile) + case .progress: + break + default: + break + } + }) + + return EmptyDisposable + } + } + + var completedAvatar: CreatePendingPeerAvatar? + let uploadedVideo = (videoResource + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { resource -> Signal in + if let resource { + return context.engine.peers.uploadedPeerVideo(resource: EngineMediaResource(resource)) + |> map(Optional.init) + } else { + return .single(nil) + } + } + |> afterNext { next in + if let next, next.isCompleted, let completedAvatar { + didCompleteLoadingPreview(completedAvatar) + } + }) + + let pendingAvatar = CreatePendingPeerAvatar( + previewRepresentation: representation, + isLoadingPreview: true, + uploadedPhoto: uploadedPhoto, + uploadedVideo: uploadedVideo, + videoStartTimestamp: videoStartTimestamp, + markup: markup + ) + completedAvatar = CreatePendingPeerAvatar( + previewRepresentation: representation, + isLoadingPreview: false, + uploadedPhoto: uploadedPhoto, + uploadedVideo: uploadedVideo, + videoStartTimestamp: videoStartTimestamp, + markup: markup + ) + + return pendingAvatar + } +} diff --git a/submodules/TelegramUI/Sources/DisabledContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/DisabledContextResultsChatInputContextPanelNode.swift index 69025bf1fe..f86bc5defd 100644 --- a/submodules/TelegramUI/Sources/DisabledContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/DisabledContextResultsChatInputContextPanelNode.swift @@ -43,7 +43,8 @@ final class DisabledContextResultsChatInputContextPanelNode: ChatInputContextPan self.containerNode.backgroundColor = interfaceState.theme.list.plainBackgroundColor self.separatorNode.backgroundColor = interfaceState.theme.list.itemPlainSeparatorColor - guard let (untilDate, personal) = (interfaceState.renderedPeer?.peer as? TelegramChannel)?.hasBannedPermission(.banSendInline) else { + let canBypass = canBypassRestrictions(chatPresentationInterfaceState: interfaceState) + guard let (untilDate, personal) = (interfaceState.renderedPeer?.peer as? TelegramChannel)?.hasBannedPermission(.banSendInline, ignoreDefault: canBypass) else { return } let banDescription: String diff --git a/submodules/WebSearchUI/Sources/WebSearchController.swift b/submodules/WebSearchUI/Sources/WebSearchController.swift index 9e960e9a63..32a0fa1aef 100644 --- a/submodules/WebSearchUI/Sources/WebSearchController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchController.swift @@ -16,7 +16,7 @@ public enum WebSearchMode { } public enum WebSearchControllerMode { - case media(attachment: Bool, completion: (ChatContextResultCollection, TGMediaSelectionContext, TGMediaEditingContext, Bool) -> Void) + case media(attachment: Bool, completion: (ChatContextResultCollection, TGMediaSelectionContext, TGMediaEditingContext, Bool, Int32?) -> Void) case editor(completion: (UIImage) -> Void) case avatar(initialQuery: String?, completion: (UIImage) -> Void) @@ -115,7 +115,7 @@ public final class WebSearchController: ViewController { } } - public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in } + public var presentSchedulePicker: (Bool, @escaping (Int32, Bool) -> Void) -> Void = { _, _ in } public var dismissed: () -> Void = { } @@ -261,13 +261,13 @@ public final class WebSearchController: ViewController { selectionState.setItem(currentItem, selected: true) } if case let .media(_, sendSelected) = mode { - sendSelected(results, selectionState, editingState, false) + sendSelected(results, selectionState, editingState, silently, scheduleTime) } } }, schedule: { [weak self] messageEffect in if let strongSelf = self { - strongSelf.presentSchedulePicker(false, { [weak self] time in - self?.controllerInteraction?.sendSelected(nil, false, time, nil) + strongSelf.presentSchedulePicker(false, { [weak self] time, silentPosting in + self?.controllerInteraction?.sendSelected(nil, silentPosting, time, nil) }) } }, avatarCompleted: { result in From 96b1432434205e2d09d7615bde1402d762ac2b8c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 24 Apr 2026 04:55:22 +0200 Subject: [PATCH 8/8] Various improvements --- .../Sources/AccountContext.swift | 18 +- .../Sources/AttachmentPanel.swift | 2 +- .../ChatListFilterPresetController.swift | 1 - .../ChatPresentationInterfaceState.swift | 189 +++++++++--------- .../Sources/ICloudResources.swift | 84 +++++++- .../Sources/VideoChatScreen.swift | 1 - .../Sources/ApiUtils/ApiUtils.swift | 96 +++++++++ .../State/AccountStateManagementUtils.swift | 3 +- .../ManagedSecretChatOutgoingOperations.swift | 2 +- .../Messages/ReportContent.swift | 12 +- .../TelegramEngine/Peers/ReportPeer.swift | 14 +- .../Peers/TelegramEnginePeers.swift | 16 +- .../Peers/UpdateCachedPeerData.swift | 4 +- .../TelegramEngine/Privacy/BlockedPeers.swift | 4 +- .../Privacy/TelegramEnginePrivacy.swift | 4 +- .../ChatEmptyNode/Sources/ChatEmptyNode.swift | 178 +---------------- .../Sources/ChatTextInputPanelComponent.swift | 2 - .../Sources/ChatEntityKeyboardInputNode.swift | 1 - .../Sources/ComposePollScreen.swift | 3 - .../Sources/ComposeTodoScreen.swift | 1 - .../Sources/GiftSetupScreen.swift | 3 - .../Sources/LegacyMessageInputPanel.swift | 1 - .../Sources/MediaEditorScreen.swift | 1 - .../PeerInfoScreen/Sources/PeerInfoData.swift | 153 +++++++------- .../Sources/PeerInfoProfileItems.swift | 20 +- .../Sources/PeerInfoScreen.swift | 66 +++--- .../Sources/PeerInfoScreenOpenChat.swift | 50 +---- .../PeerInfoScreenPerformButtonAction.swift | 15 +- .../PeerInfoScreenSettingsActions.swift | 1 - .../Sources/PeerInfoSelectionPanelNode.swift | 2 +- .../Sources/PeerReportScreen.swift | 10 +- .../Sources/PeerSelectionControllerNode.swift | 2 +- .../Sources/ChatIntroItemComponent.swift | 1 - ...StoryItemSetContainerViewSendMessage.swift | 3 +- .../Sources/Chat/ChatControllerOpenPeer.swift | 4 +- .../TelegramUI/Sources/ChatController.swift | 3 +- .../ChatControllerOpenAttachmentMenu.swift | 2 +- .../Sources/NavigateToChatController.swift | 2 +- .../OverlayAudioPlayerController.swift | 2 +- .../Sources/SharedAccountContext.swift | 21 +- .../Sources/TelegramRootController.swift | 6 +- 41 files changed, 463 insertions(+), 540 deletions(-) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 3d5fffc634..51ee93b7d1 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -408,18 +408,6 @@ public final class ChatPeekTimeout { } } -public final class ChatPeerNearbyData: Equatable { - public static func == (lhs: ChatPeerNearbyData, rhs: ChatPeerNearbyData) -> Bool { - return lhs.distance == rhs.distance - } - - public let distance: Int32 - - public init(distance: Int32) { - self.distance = distance - } -} - public final class ChatGreetingData: Equatable { public static func == (lhs: ChatGreetingData, rhs: ChatGreetingData) -> Bool { return lhs.uuid == rhs.uuid @@ -587,7 +575,6 @@ public final class NavigateToChatControllerParams { public let scrollToEndIfExists: Bool public let activateMessageSearch: (ChatSearchDomain, String)? public let peekData: ChatPeekTimeout? - public let peerNearbyData: ChatPeerNearbyData? public let reportReason: NavigateToChatControllerParams.ReportReason? public let animated: Bool public let forceAnimatedScroll: Bool @@ -623,7 +610,6 @@ public final class NavigateToChatControllerParams { scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, - peerNearbyData: ChatPeerNearbyData? = nil, reportReason: NavigateToChatControllerParams.ReportReason? = nil, animated: Bool = true, forceAnimatedScroll: Bool = false, @@ -658,7 +644,6 @@ public final class NavigateToChatControllerParams { self.scrollToEndIfExists = scrollToEndIfExists self.activateMessageSearch = activateMessageSearch self.peekData = peekData - self.peerNearbyData = peerNearbyData self.reportReason = reportReason self.animated = animated self.forceAnimatedScroll = forceAnimatedScroll @@ -696,7 +681,6 @@ public final class NavigateToChatControllerParams { scrollToEndIfExists: self.scrollToEndIfExists, activateMessageSearch: self.activateMessageSearch, peekData: self.peekData, - peerNearbyData: self.peerNearbyData, reportReason: self.reportReason, animated: self.animated, forceAnimatedScroll: self.forceAnimatedScroll, @@ -753,7 +737,7 @@ public enum PeerInfoControllerMode { case generic case calls(messages: [Message]) case nearbyPeer(distance: Int32) - case group(PeerId) + case group(sourceMessageId: MessageId) case reaction(MessageId) case forumTopic(thread: ChatReplyThreadMessage) case recommendedChannels diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 21c109bb68..4b2d4a776a 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -1083,7 +1083,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate, ASGestureRecog self.isScheduledMessages = isScheduledMessages self.customEmojiAvailable = customEmojiAvailable - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: chatLocation ?? .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil).updatedCustomEmojiAvailable(customEmojiAvailable) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: chatLocation ?? .peer(id: context.account.peerId), subject: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil).updatedCustomEmojiAvailable(customEmojiAvailable) self.containerNode = ASDisplayNode() self.containerNode.clipsToBounds = false diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index d85f03cf88..75b9cf8733 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -1281,7 +1281,6 @@ private final class ChatListFilterPresetController: ItemListController { mode: .standard(.default), chatLocation: .peer(id: context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift index f554ef297b..fdd4029b3e 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift @@ -541,7 +541,6 @@ public final class ChatPresentationInterfaceState: Equatable { public let hasScheduledMessages: Bool public let autoremoveTimeout: Int32? public let subject: ChatControllerSubject? - public let peerNearbyData: ChatPeerNearbyData? public let greetingData: ChatGreetingData? public let pendingUnpinnedAllMessages: Bool public let activeGroupCallInfo: ChatActiveGroupCallInfo? @@ -590,7 +589,7 @@ public final class ChatPresentationInterfaceState: Equatable { public let viewForumAsMessages: Bool public let hasTopics: Bool - public init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, preferredGlassType: GlassType, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation, subject: ChatControllerSubject?, peerNearbyData: ChatPeerNearbyData?, greetingData: ChatGreetingData?, pendingUnpinnedAllMessages: Bool, activeGroupCallInfo: ChatActiveGroupCallInfo?, hasActiveGroupCall: Bool, threadData: ThreadData?, isGeneralThreadClosed: Bool?, replyMessage: Message?, accountPeerColor: AccountPeerColor?, businessIntro: TelegramBusinessIntro?) { + public init(chatWallpaper: TelegramWallpaper, theme: PresentationTheme, preferredGlassType: GlassType, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, limitsConfiguration: LimitsConfiguration, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation, subject: ChatControllerSubject?, greetingData: ChatGreetingData?, pendingUnpinnedAllMessages: Bool, activeGroupCallInfo: ChatActiveGroupCallInfo?, hasActiveGroupCall: Bool, threadData: ThreadData?, isGeneralThreadClosed: Bool?, replyMessage: Message?, accountPeerColor: AccountPeerColor?, businessIntro: TelegramBusinessIntro?) { self.interfaceState = ChatInterfaceState() self.inputTextPanelState = ChatTextInputPanelState() self.editMessageState = nil @@ -639,7 +638,6 @@ public final class ChatPresentationInterfaceState: Equatable { self.hasScheduledMessages = false self.autoremoveTimeout = nil self.subject = subject - self.peerNearbyData = peerNearbyData self.greetingData = greetingData self.pendingUnpinnedAllMessages = pendingUnpinnedAllMessages self.activeGroupCallInfo = activeGroupCallInfo @@ -740,7 +738,6 @@ public final class ChatPresentationInterfaceState: Equatable { hasScheduledMessages: Bool, autoremoveTimeout: Int32?, subject: ChatControllerSubject?, - peerNearbyData: ChatPeerNearbyData?, greetingData: ChatGreetingData?, pendingUnpinnedAllMessages: Bool, activeGroupCallInfo: ChatActiveGroupCallInfo?, @@ -837,7 +834,6 @@ public final class ChatPresentationInterfaceState: Equatable { self.hasScheduledMessages = hasScheduledMessages self.autoremoveTimeout = autoremoveTimeout self.subject = subject - self.peerNearbyData = peerNearbyData self.greetingData = greetingData self.pendingUnpinnedAllMessages = pendingUnpinnedAllMessages self.activeGroupCallInfo = activeGroupCallInfo @@ -1041,9 +1037,6 @@ public final class ChatPresentationInterfaceState: Equatable { if lhs.subject != rhs.subject { return false } - if lhs.peerNearbyData != rhs.peerNearbyData { - return false - } if lhs.greetingData != rhs.greetingData { return false } @@ -1189,43 +1182,43 @@ public final class ChatPresentationInterfaceState: Equatable { } public func updatedInterfaceState(_ f: (ChatInterfaceState) -> ChatInterfaceState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedFocusedPollAddOptionMessageId(_ focusedPollAddOptionMessageId: MessageId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedChatLocation(_ chatLocation: ChatLocation) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeer(_ f: (RenderedPeer?) -> RenderedPeer?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsNotAccessible(_ isNotAccessible: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedExplicitelyCanPinMessages(_ explicitelyCanPinMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedContactStatus(_ contactStatus: ChatContactStatus?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsManagedBot(_ isManagedBot: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasBots(_ hasBots: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsArchived(_ isArchived: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedInputQueryResult(queryKind: ChatPresentationInputQueryKind, _ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { @@ -1242,323 +1235,323 @@ public final class ChatPresentationInterfaceState: Equatable { inputQueryResults.removeValue(forKey: queryKind) } - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedInputTextPanelState(_ f: (ChatTextInputPanelState) -> ChatTextInputPanelState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedEditMessageState(_ editMessageState: ChatEditInterfaceMessageState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedInputMode(_ f: (ChatInputMode) -> ChatInputMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedTitlePanelContext(_ f: ([ChatTitlePanelContext]) -> [ChatTitlePanelContext]) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedKeyboardButtonsMessage(_ message: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPinnedMessage(_ pinnedMessage: ChatPinnedMessage?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeerIsBlocked(_ peerIsBlocked: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeerIsMuted(_ peerIsMuted: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeerDiscussionId(_ peerDiscussionId: PeerId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedCallsAvailable(_ callsAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedCallsPrivate(_ callsPrivate: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSlowmodeState(_ slowmodeState: ChatSlowmodeState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedBotStartPayload(_ botStartPayload: String?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedChatHistoryState(_ chatHistoryState: ChatHistoryNodeHistoryState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedUrlPreview(_ urlPreview: UrlPreview?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedEditingUrlPreview(_ editingUrlPreview: UrlPreview?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSearch(_ search: ChatSearchData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSearchQuerySuggestionResult(_ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHistoryFilter(_ historyFilter: HistoryFilter?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedDisplayHistoryFilterAsList(_ displayHistoryFilterAsList: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedMode(_ mode: ChatControllerPresentationMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPresentationReady(_ presentationReady: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedTheme(_ theme: PresentationTheme) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPreferredGlassType(_ glassType: GlassType) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: glassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: glassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedStrings(_ strings: PresentationStrings) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedDateTimeFormat(_ dateTimeFormat: PresentationDateTimeFormat) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedBubbleCorners(_ bubbleCorners: PresentationChatBubbleCorners) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSubject(_ subject: ChatControllerSubject?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAutoremoveTimeout(_ autoremoveTimeout: Int32?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPendingUnpinnedAllMessages(_ pendingUnpinnedAllMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedActiveGroupCallInfo(_ activeGroupCallInfo: ChatActiveGroupCallInfo?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasActiveGroupCall(_ hasActiveGroupCall: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedReportReason(_ reportReason: ReportReasonData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedShowCommands(_ showCommands: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasBotCommands(_ hasBotCommands: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedShowSendAsPeers(_ showSendAsPeers: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSendAsPeers(_ sendAsPeers: [SendAsPeer]?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedCurrentSendAsPeerId(_ currentSendAsPeerId: PeerId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedBotMenuButton(_ botMenuButton: BotMenuButton) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedShowWebView(_ showWebView: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedCopyProtectionEnabled(_ copyProtectionEnabled: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedMyCopyProtectionEnabled(_ myCopyProtectionEnabled: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasAtLeast3Messages(_ hasAtLeast3Messages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasPlentyOfMessages(_ hasPlentyOfMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsPremium(_ isPremium: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPremiumGiftOptions(_ premiumGiftOptions: [CachedPremiumGiftOption]) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSuggestPremiumGift(_ suggestPremiumGift: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedForceInputCommandsHidden(_ forceInputCommandsHidden: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedVoiceMessagesAvailable(_ voiceMessagesAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedCustomEmojiAvailable(_ customEmojiAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedThreadData(_ threadData: ThreadData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedForumTopicData(_ forumTopicData: ThreadData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsGeneralThreadClosed(_ isGeneralThreadClosed: Bool?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedTranslationState(_ translationState: ChatPresentationTranslationState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedReplyMessage(_ replyMessage: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAccountPeerColor(_ accountPeerColor: AccountPeerColor?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSavedMessagesTopicPeer(_ savedMessagesTopicPeer: EnginePeer?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasSearchTags(_ hasSearchTags: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedIsPremiumRequiredForMessaging(_ isPremiumRequiredForMessaging: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedSendPaidMessageStars(_ sendPaidMessageStars: StarsAmount?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAcknowledgedPaidMessage(_ acknowledgedPaidMessage: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasSavedChats(_ hasSavedChats: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAppliedBoosts(_ appliedBoosts: Int32?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedBoostsToUnrestrict(_ boostsToUnrestrict: Int32?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedBusinessIntro(_ businessIntro: TelegramBusinessIntro?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasBirthdayToday(_ hasBirthdayToday: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAdMessage(_ adMessage: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPeerVerification(_ peerVerification: PeerVerification?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedStarGiftsAvailable(_ starGiftsAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedAlwaysShowGiftButton(_ alwaysShowGiftButton: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedDisallowedGifts(_ disallowedGifts: TelegramDisallowedGifts?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedPersistentData(_ persistentData: PersistentPeerData) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedRemovePaidMessageFeeData(_ removePaidMessageFeeData: RemovePaidMessageFeeData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedViewForumAsMessages(_ viewForumAsMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: viewForumAsMessages, hasTopics: self.hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: viewForumAsMessages, hasTopics: self.hasTopics) } public func updatedHasTopics(_ hasTopics: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, peerNearbyData: self.peerNearbyData, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: hasTopics) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, contactStatus: self.contactStatus, isManagedBot: self.isManagedBot, hasBots: self.hasBots, isArchived: self.isArchived, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, focusedPollAddOptionMessageId: self.focusedPollAddOptionMessageId, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, peerDiscussionId: self.peerDiscussionId, peerGeoLocation: self.peerGeoLocation, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, slowmodeState: self.slowmodeState, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, historyFilter: self.historyFilter, displayHistoryFilterAsList: self.displayHistoryFilterAsList, presentationReady: self.presentationReady, chatWallpaper: self.chatWallpaper, theme: self.theme, preferredGlassType: self.preferredGlassType, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, limitsConfiguration: self.limitsConfiguration, fontSize: self.fontSize, bubbleCorners: self.bubbleCorners, accountPeerId: self.accountPeerId, mode: self.mode, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, subject: self.subject, greetingData: self.greetingData, pendingUnpinnedAllMessages: self.pendingUnpinnedAllMessages, activeGroupCallInfo: self.activeGroupCallInfo, hasActiveGroupCall: self.hasActiveGroupCall, reportReason: self.reportReason, showCommands: self.showCommands, hasBotCommands: self.hasBotCommands, showSendAsPeers: self.showSendAsPeers, sendAsPeers: self.sendAsPeers, botMenuButton: self.botMenuButton, showWebView: self.showWebView, currentSendAsPeerId: self.currentSendAsPeerId, copyProtectionEnabled: self.copyProtectionEnabled, myCopyProtectionEnabled: self.myCopyProtectionEnabled, hasAtLeast3Messages: self.hasAtLeast3Messages, hasPlentyOfMessages: self.hasPlentyOfMessages, isPremium: self.isPremium, premiumGiftOptions: self.premiumGiftOptions, suggestPremiumGift: self.suggestPremiumGift, forceInputCommandsHidden: self.forceInputCommandsHidden, voiceMessagesAvailable: self.voiceMessagesAvailable, customEmojiAvailable: self.customEmojiAvailable, threadData: self.threadData, forumTopicData: self.forumTopicData, isGeneralThreadClosed: self.isGeneralThreadClosed, translationState: self.translationState, replyMessage: self.replyMessage, accountPeerColor: self.accountPeerColor, savedMessagesTopicPeer: self.savedMessagesTopicPeer, hasSearchTags: self.hasSearchTags, isPremiumRequiredForMessaging: self.isPremiumRequiredForMessaging, sendPaidMessageStars: self.sendPaidMessageStars, acknowledgedPaidMessage: self.acknowledgedPaidMessage, hasSavedChats: self.hasSavedChats, appliedBoosts: self.appliedBoosts, boostsToUnrestrict: self.boostsToUnrestrict, businessIntro: self.businessIntro, hasBirthdayToday: self.hasBirthdayToday, adMessage: self.adMessage, peerVerification: self.peerVerification, starGiftsAvailable: self.starGiftsAvailable, alwaysShowGiftButton: self.alwaysShowGiftButton, disallowedGifts: self.disallowedGifts, persistentData: self.persistentData, removePaidMessageFeeData: self.removePaidMessageFeeData, viewForumAsMessages: self.viewForumAsMessages, hasTopics: hasTopics) } } diff --git a/submodules/ICloudResources/Sources/ICloudResources.swift b/submodules/ICloudResources/Sources/ICloudResources.swift index 2ccf30e87f..9658b88460 100644 --- a/submodules/ICloudResources/Sources/ICloudResources.swift +++ b/submodules/ICloudResources/Sources/ICloudResources.swift @@ -68,6 +68,7 @@ public struct ICloudFileDescription { public let title: String? public let performer: String? public let duration: Int + public let hasAudioArtwork: Bool } public let urlData: String @@ -76,6 +77,51 @@ public struct ICloudFileDescription { public let audioMetadata: AudioMetadata? } +private let audioFileExtensions: Set = ["mp3", "m4a", "aac", "flac"] + +private func validatedAudioArtworkData(_ data: Data?) -> Data? { + guard let data, UIImage(data: data) != nil else { + return nil + } + return data +} + +private func audioArtworkData(from metadataItem: AVMetadataItem) -> Data? { + if let data = validatedAudioArtworkData(metadataItem.value(forKey: "dataValue") as? Data) { + return data + } + if let data = metadataItem.value(forKey: "value") as? Data { + return validatedAudioArtworkData(data) + } + if let data = metadataItem.value(forKey: "value") as? NSData { + return validatedAudioArtworkData(data as Data) + } + return nil +} + +private func audioArtworkData(from asset: AVURLAsset) -> Data? { + func firstArtworkData(in metadataItems: [AVMetadataItem]) -> Data? { + for item in metadataItems { + if item.commonKey == AVMetadataKey.commonKeyArtwork, let data = audioArtworkData(from: item) { + return data + } + } + return nil + } + + if let data = firstArtworkData(in: asset.commonMetadata) { + return data + } + + for format in asset.availableMetadataFormats { + if let data = firstArtworkData(in: asset.metadata(forFormat: format)) { + return data + } + } + + return nil +} + private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? { if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { guard url.startAccessingSecurityScopedResource() else { @@ -96,16 +142,23 @@ private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? { var audioMetadata: ICloudFileDescription.AudioMetadata? let fileExtension = url.pathExtension.lowercased() - if ["mp3", "m4a"].contains(fileExtension) { + var hasAudioArtwork = false + let audioAsset: AVURLAsset? + if audioFileExtensions.contains(fileExtension) { let asset = AVURLAsset(url: url) + audioAsset = asset + hasAudioArtwork = audioArtworkData(from: asset) != nil + } else { + audioAsset = nil + } + if ["mp3", "m4a"].contains(fileExtension), let asset = audioAsset { let title = AVMetadataItem.metadataItems(from: asset.commonMetadata, withKey: AVMetadataKey.commonKeyTitle, keySpace: AVMetadataKeySpace.common).first?.stringValue let performer = AVMetadataItem.metadataItems(from: asset.commonMetadata, withKey: AVMetadataKey.commonKeyArtist, keySpace: AVMetadataKeySpace.common).first?.stringValue let duration = CMTimeGetSeconds(asset.duration) if duration > 0 { - audioMetadata = ICloudFileDescription.AudioMetadata(title: title, performer: performer, duration: Int(duration)) + audioMetadata = ICloudFileDescription.AudioMetadata(title: title, performer: performer, duration: Int(duration), hasAudioArtwork: hasAudioArtwork) } - } else if fileExtension == "flac" { - let asset = AVURLAsset(url: url) + } else if fileExtension == "flac", let asset = audioAsset { var title: String? var performer: String? let vorbisComment = AVMetadataFormat(rawValue: "org.xiph.vorbis-comment") @@ -122,11 +175,16 @@ private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? { } let duration = CMTimeGetSeconds(asset.duration) if duration > 0 { - audioMetadata = ICloudFileDescription.AudioMetadata(title: title, performer: performer, duration: Int(duration)) + audioMetadata = ICloudFileDescription.AudioMetadata(title: title, performer: performer, duration: Int(duration), hasAudioArtwork: hasAudioArtwork) } } - let result = ICloudFileDescription(urlData: urlData.base64EncodedString(), fileName: fileName, fileSize: fileSize, audioMetadata: audioMetadata) + let result = ICloudFileDescription( + urlData: urlData.base64EncodedString(), + fileName: fileName, + fileSize: fileSize, + audioMetadata: audioMetadata + ) url.stopAccessingSecurityScopedResource() @@ -250,11 +308,17 @@ public func fetchICloudFileResource(resource: ICloudFileResource) -> Signal Api.InputPeer? { } } +private func apiInputPeerFromSourceMessage(_ sourceMessageId: MessageId?, transaction: Transaction) -> (MessageId, Api.InputPeer)? { + guard let sourceMessageId else { + return nil + } + guard let sourcePeer = transaction.getPeer(sourceMessageId.peerId) else { + return nil + } + guard let inputPeer = apiInputPeer(sourcePeer) else { + return nil + } + return (sourceMessageId, inputPeer) +} + +func apiInputPeer(_ peer: Peer, sourceMessageId: MessageId?, transaction: Transaction) -> Api.InputPeer? { + switch peer { + case let user as TelegramUser: + if let accessHash = user.accessHash { + switch accessHash { + case let .personal(value): + return Api.InputPeer.inputPeerUser(.init(userId: user.id.id._internalGetInt64Value(), accessHash: value)) + case let .genericPublic(value): + if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputPeer.inputPeerUserFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, userId: user.id.id._internalGetInt64Value())) + } + return Api.InputPeer.inputPeerUser(.init(userId: user.id.id._internalGetInt64Value(), accessHash: value)) + } + } else if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputPeer.inputPeerUserFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, userId: user.id.id._internalGetInt64Value())) + } else { + return nil + } + case let group as TelegramGroup: + return Api.InputPeer.inputPeerChat(.init(chatId: group.id.id._internalGetInt64Value())) + case let channel as TelegramChannel: + if let accessHash = channel.accessHash { + switch accessHash { + case let .personal(value): + return Api.InputPeer.inputPeerChannel(.init(channelId: channel.id.id._internalGetInt64Value(), accessHash: value)) + case let .genericPublic(value): + if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputPeer.inputPeerChannelFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, channelId: channel.id.id._internalGetInt64Value())) + } + return Api.InputPeer.inputPeerChannel(.init(channelId: channel.id.id._internalGetInt64Value(), accessHash: value)) + } + } else if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputPeer.inputPeerChannelFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, channelId: channel.id.id._internalGetInt64Value())) + } else { + return nil + } + default: + return nil + } +} + func apiInputPeerOrSelf(_ peer: Peer, accountPeerId: PeerId) -> Api.InputPeer? { if peer.id == accountPeerId { return .inputPeerSelf @@ -94,6 +148,27 @@ func apiInputChannel(_ peer: Peer) -> Api.InputChannel? { } } +func apiInputChannel(_ peer: Peer, sourceMessageId: MessageId?, transaction: Transaction) -> Api.InputChannel? { + guard let channel = peer as? TelegramChannel else { + return nil + } + if let accessHash = channel.accessHash { + switch accessHash { + case let .personal(value): + return Api.InputChannel.inputChannel(.init(channelId: channel.id.id._internalGetInt64Value(), accessHash: value)) + case let .genericPublic(value): + if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputChannel.inputChannelFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, channelId: channel.id.id._internalGetInt64Value())) + } + return Api.InputChannel.inputChannel(.init(channelId: channel.id.id._internalGetInt64Value(), accessHash: value)) + } + } else if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputChannel.inputChannelFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, channelId: channel.id.id._internalGetInt64Value())) + } else { + return nil + } +} + func apiInputUser(_ peer: Peer) -> Api.InputUser? { if let user = peer as? TelegramUser, let accessHash = user.accessHash { return Api.InputUser.inputUser(.init(userId: user.id.id._internalGetInt64Value(), accessHash: accessHash.value)) @@ -102,6 +177,27 @@ func apiInputUser(_ peer: Peer) -> Api.InputUser? { } } +func apiInputUser(_ peer: Peer, sourceMessageId: MessageId?, transaction: Transaction) -> Api.InputUser? { + guard let user = peer as? TelegramUser else { + return nil + } + if let accessHash = user.accessHash { + switch accessHash { + case let .personal(value): + return Api.InputUser.inputUser(.init(userId: user.id.id._internalGetInt64Value(), accessHash: value)) + case let .genericPublic(value): + if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputUser.inputUserFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, userId: user.id.id._internalGetInt64Value())) + } + return Api.InputUser.inputUser(.init(userId: user.id.id._internalGetInt64Value(), accessHash: value)) + } + } else if let (sourceMessageId, sourcePeer) = apiInputPeerFromSourceMessage(sourceMessageId, transaction: transaction) { + return Api.InputUser.inputUserFromMessage(.init(peer: sourcePeer, msgId: sourceMessageId.id, userId: user.id.id._internalGetInt64Value())) + } else { + return nil + } +} + func apiInputSecretChat(_ peer: Peer) -> Api.InputEncryptedChat? { if let chat = peer as? TelegramSecretChat { return Api.InputEncryptedChat.inputEncryptedChat(.init(chatId: Int32(peer.id.id._internalGetInt64Value()), accessHash: chat.accessHash)) diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 37fe0b2cbd..2dc0e2ea97 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -5889,6 +5889,7 @@ func replayFinalState( var addedSecretMessageIds: [MessageId] = [] var addedSecretMessageAuthorIds: [PeerId: PeerId] = [:] + let keepArchivedUnmuted = fetchGlobalPrivacySettings(transaction: transaction).keepArchivedUnmuted for peerId in peerIdsWithAddedSecretMessages { inner: while true { @@ -5897,7 +5898,7 @@ func replayFinalState( let processResult = processSecretChatIncomingDecryptedOperations(encryptionProvider: encryptionProvider, mediaBox: mediaBox, transaction: transaction, peerId: peerId) if !processResult.addedMessages.isEmpty { let currentInclusion = transaction.getPeerChatListInclusion(peerId) - if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive { + if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive, !keepArchivedUnmuted { if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: transaction.getGlobalNotificationSettings(), peer: peer, peerSettings: transaction.getPeerNotificationSettings(id: peer.regularPeerId)) diff --git a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift index 1ebe2f011e..5e2cdf1b07 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift @@ -1889,7 +1889,7 @@ private func sendStandaloneMessage(auxiliaryMethods: AccountAuxiliaryMethods, po var attributes = contents.attributes if !attributes.contains(where: { $0 is AutoremoveTimeoutMessageAttribute }), let messageAutoremoveTimeout = state.messageAutoremoveTimeout { - attributes.append(AutoclearTimeoutMessageAttribute(timeout: messageAutoremoveTimeout, countdownBeginTime: nil)) + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: messageAutoremoveTimeout, countdownBeginTime: nil)) } let message = Message( diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReportContent.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReportContent.swift index 4334c6ace5..bf261814fa 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReportContent.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReportContent.swift @@ -21,13 +21,13 @@ public enum ReportContentError { } public enum ReportContentSubject: Equatable { - case peer(EnginePeer.Id) + case peer(EnginePeer.Id, sourceMessageId: EngineMessage.Id? = nil) case messages([EngineMessage.Id]) case stories(EnginePeer.Id, [Int32]) public var peerId: EnginePeer.Id { switch self { - case let .peer(peerId): + case let .peer(peerId, _): return peerId case let .messages(messageIds): return messageIds.first!.peerId @@ -39,7 +39,13 @@ public enum ReportContentSubject: Equatable { func _internal_reportContent(account: Account, subject: ReportContentSubject, option: Data?, message: String?) -> Signal { return account.postbox.transaction { transaction -> Signal in - guard let peer = transaction.getPeer(subject.peerId), let inputPeer = apiInputPeer(peer) else { + let sourceMessageId: MessageId? + if case let .peer(_, messageId) = subject { + sourceMessageId = messageId + } else { + sourceMessageId = nil + } + guard let peer = transaction.getPeer(subject.peerId), let inputPeer = apiInputPeer(peer, sourceMessageId: sourceMessageId, transaction: transaction) else { return .fail(.generic) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ReportPeer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ReportPeer.swift index 54ede971c6..ba2969cd40 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ReportPeer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ReportPeer.swift @@ -5,7 +5,7 @@ import TelegramApi import MtProtoKit -func _internal_reportPeer(account: Account, peerId: PeerId) -> Signal { +func _internal_reportPeer(account: Account, peerId: PeerId, sourceMessageId: MessageId? = nil) -> Signal { return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId) { if let peer = peer as? TelegramSecretChat { @@ -37,7 +37,7 @@ func _internal_reportPeer(account: Account, peerId: PeerId) -> Signal map(Optional.init) |> `catch` { _ -> Signal in @@ -115,9 +115,9 @@ private extension ReportReason { } } -func _internal_reportPeer(account: Account, peerId: PeerId, reason: ReportReason, message: String) -> Signal { +func _internal_reportPeer(account: Account, peerId: PeerId, reason: ReportReason, message: String, sourceMessageId: MessageId? = nil) -> Signal { return account.postbox.transaction { transaction -> Signal in - if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer, sourceMessageId: sourceMessageId, transaction: transaction) { return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason, message: message)) |> `catch` { _ -> Signal in return .single(.boolFalse) @@ -131,9 +131,9 @@ func _internal_reportPeer(account: Account, peerId: PeerId, reason: ReportReason } |> switchToLatest } -func _internal_reportPeerPhoto(account: Account, peerId: PeerId, reason: ReportReason, message: String) -> Signal { +func _internal_reportPeerPhoto(account: Account, peerId: PeerId, reason: ReportReason, message: String, sourceMessageId: MessageId? = nil) -> Signal { return account.postbox.transaction { transaction -> Signal in - if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer, sourceMessageId: sourceMessageId, transaction: transaction) { return account.network.request(Api.functions.account.reportProfilePhoto(peer: inputPeer, photoId: .inputPhotoEmpty, reason: reason.apiReason, message: message)) |> `catch` { _ -> Signal in return .single(.boolFalse) @@ -193,7 +193,7 @@ func _internal_reportPeerReaction(account: Account, authorId: PeerId, messageId: guard let peer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else { return nil } - guard let author = transaction.getPeer(authorId).flatMap(apiInputPeer) else { + guard let authorPeer = transaction.getPeer(authorId), let author = apiInputPeer(authorPeer, sourceMessageId: messageId, transaction: transaction) else { return nil } return (peer, author) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 9e64bc8b99..5875920205 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -336,16 +336,16 @@ public extension TelegramEngine { return _internal_updateChannelSlowModeInteractively(postbox: self.account.postbox, network: self.account.network, accountStateManager: self.account.stateManager, peerId: peerId, timeout: timeout) } - public func reportPeer(peerId: PeerId) -> Signal { - return _internal_reportPeer(account: self.account, peerId: peerId) + public func reportPeer(peerId: PeerId, sourceMessageId: MessageId? = nil) -> Signal { + return _internal_reportPeer(account: self.account, peerId: peerId, sourceMessageId: sourceMessageId) } - public func reportPeer(peerId: PeerId, reason: ReportReason, message: String) -> Signal { - return _internal_reportPeer(account: self.account, peerId: peerId, reason: reason, message: message) + public func reportPeer(peerId: PeerId, reason: ReportReason, message: String, sourceMessageId: MessageId? = nil) -> Signal { + return _internal_reportPeer(account: self.account, peerId: peerId, reason: reason, message: message, sourceMessageId: sourceMessageId) } - public func reportPeerPhoto(peerId: PeerId, reason: ReportReason, message: String) -> Signal { - return _internal_reportPeerPhoto(account: self.account, peerId: peerId, reason: reason, message: message) + public func reportPeerPhoto(peerId: PeerId, reason: ReportReason, message: String, sourceMessageId: MessageId? = nil) -> Signal { + return _internal_reportPeerPhoto(account: self.account, peerId: peerId, reason: reason, message: message, sourceMessageId: sourceMessageId) } public func reportPeerMessages(messageIds: [MessageId], reason: ReportReason, message: String) -> Signal { @@ -823,8 +823,8 @@ public extension TelegramEngine { } } - public func fetchAndUpdateCachedPeerData(peerId: PeerId) -> Signal { - return _internal_fetchAndUpdateCachedPeerData(accountPeerId: self.account.peerId, peerId: peerId, network: self.account.network, postbox: self.account.postbox) + public func fetchAndUpdateCachedPeerData(peerId: PeerId, sourceMessageId: EngineMessage.Id? = nil) -> Signal { + return _internal_fetchAndUpdateCachedPeerData(accountPeerId: self.account.peerId, peerId: peerId, sourceMessageId: sourceMessageId, network: self.account.network, postbox: self.account.postbox) } public func toggleItemPinned(location: TogglePeerChatPinnedLocation, itemId: PinnedItemId) -> Signal { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index fd6a7c9b32..41dede4909 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -140,7 +140,7 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountP } } -func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerId, network: Network, postbox: Postbox) -> Signal { +func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerId, sourceMessageId: EngineMessage.Id? = nil, network: Network, postbox: Postbox) -> Signal { return postbox.combinedView(keys: [.basicPeer(rawPeerId)]) |> mapToSignal { views -> Signal in if accountPeerId == rawPeerId { @@ -178,7 +178,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee if rawPeerId == accountPeerId { return (.inputUserSelf, rawPeer, rawPeerId) } else { - return (apiInputUser(peer), peer, peer.id) + return (apiInputUser(peer, sourceMessageId: sourceMessageId, transaction: transaction), peer, peer.id) } } |> mapToSignal { inputUser, maybePeer, peerId -> Signal in diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/BlockedPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/BlockedPeers.swift index 1a300fe33e..a724c1ca7f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/BlockedPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/BlockedPeers.swift @@ -4,9 +4,9 @@ import SwiftSignalKit import TelegramApi import MtProtoKit -func _internal_requestUpdatePeerIsBlocked(account: Account, peerId: PeerId, isBlocked: Bool) -> Signal { +func _internal_requestUpdatePeerIsBlocked(account: Account, peerId: PeerId, isBlocked: Bool, sourceMessageId: MessageId? = nil) -> Signal { return account.postbox.transaction { transaction -> Signal in - if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer, sourceMessageId: sourceMessageId, transaction: transaction) { let signal: Signal if isBlocked { signal = account.network.request(Api.functions.contacts.block(flags: 0, id: inputPeer)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift index 05061edcee..1a4c8ce215 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift @@ -9,8 +9,8 @@ public extension TelegramEngine { self.account = account } - public func requestUpdatePeerIsBlocked(peerId: PeerId, isBlocked: Bool) -> Signal { - return _internal_requestUpdatePeerIsBlocked(account: self.account, peerId: peerId, isBlocked: isBlocked) + public func requestUpdatePeerIsBlocked(peerId: PeerId, isBlocked: Bool, sourceMessageId: MessageId? = nil) -> Signal { + return _internal_requestUpdatePeerIsBlocked(account: self.account, peerId: peerId, isBlocked: isBlocked, sourceMessageId: sourceMessageId) } public func requestUpdatePeerIsBlockedFromStories(peerId: PeerId, isBlocked: Bool) -> Signal { diff --git a/submodules/TelegramUI/Components/Chat/ChatEmptyNode/Sources/ChatEmptyNode.swift b/submodules/TelegramUI/Components/Chat/ChatEmptyNode/Sources/ChatEmptyNode.swift index bfee82ed6b..79f11f91bb 100644 --- a/submodules/TelegramUI/Components/Chat/ChatEmptyNode/Sources/ChatEmptyNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatEmptyNode/Sources/ChatEmptyNode.swift @@ -297,177 +297,6 @@ public final class ChatEmptyNodeGreetingChatContent: ASDisplayNode, ChatEmptyNod } } -public final class ChatEmptyNodeNearbyChatContent: ASDisplayNode, ChatEmptyNodeStickerContentNode, ChatEmptyNodeContent, ASGestureRecognizerDelegate { - private let context: AccountContext - private let interaction: ChatPanelInterfaceInteraction? - - private let titleNode: ImmediateTextNode - private let textNode: ImmediateTextNode - - private var stickerItem: ChatMediaInputStickerGridItem? - public let stickerNode: ChatMediaInputStickerGridItemNode - - private var currentTheme: PresentationTheme? - private var currentStrings: PresentationStrings? - - private var didSetupSticker = false - private let disposable = MetaDisposable() - - public init(context: AccountContext, interaction: ChatPanelInterfaceInteraction?) { - self.context = context - self.interaction = interaction - - self.titleNode = ImmediateTextNode() - self.titleNode.maximumNumberOfLines = 0 - self.titleNode.lineSpacing = 0.15 - self.titleNode.textAlignment = .center - self.titleNode.isUserInteractionEnabled = false - self.titleNode.displaysAsynchronously = false - - self.textNode = ImmediateTextNode() - self.textNode.maximumNumberOfLines = 0 - self.textNode.lineSpacing = 0.15 - self.textNode.textAlignment = .center - self.textNode.isUserInteractionEnabled = false - self.textNode.displaysAsynchronously = false - - self.stickerNode = ChatMediaInputStickerGridItemNode() - - super.init() - - self.addSubnode(self.titleNode) - self.addSubnode(self.textNode) - self.addSubnode(self.stickerNode) - } - - override public func didLoad() { - super.didLoad() - - let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.stickerTapGesture(_:))) - tapRecognizer.delegate = self.wrappedGestureRecognizerDelegate - self.stickerNode.view.addGestureRecognizer(tapRecognizer) - } - - deinit { - self.disposable.dispose() - } - - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true - } - - @objc private func stickerTapGesture(_ gestureRecognizer: UITapGestureRecognizer) { - guard let stickerItem = self.stickerItem else { - return - } - let _ = self.interaction?.sendSticker(.standalone(media: stickerItem.stickerItem.file._parse()), false, self.view, self.stickerNode.bounds, nil, []) - } - - public func updateLayout(interfaceState: ChatPresentationInterfaceState, subject: ChatEmptyNode.Subject, size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize { - if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings { - self.currentTheme = interfaceState.theme - self.currentStrings = interfaceState.strings - - var displayName = "" - let distance = interfaceState.peerNearbyData?.distance ?? 0 - - if let renderedPeer = interfaceState.renderedPeer { - if let chatPeer = renderedPeer.chatOrMonoforumMainPeer { - displayName = EnginePeer(chatPeer).compactDisplayTitle - } - } - - let titleString = interfaceState.strings.Conversation_PeerNearbyTitle(displayName, shortStringForDistance(strings: interfaceState.strings, distance: distance)).string - let serviceColor = serviceMessageColorComponents(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper) - - self.titleNode.attributedText = NSAttributedString(string: titleString, font: titleFont, textColor: serviceColor.primaryText) - - self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_PeerNearbyText, font: messageFont, textColor: serviceColor.primaryText) - } - - let stickerSize = CGSize(width: 160.0, height: 160.0) - if let item = self.stickerItem { - self.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true) - } else if !self.didSetupSticker { - let sticker: Signal - if let preloadedSticker = interfaceState.greetingData?.sticker { - sticker = preloadedSticker - } else { - sticker = self.context.engine.stickers.randomGreetingSticker() - |> map { item -> TelegramMediaFile? in - return item?.file - } - } - - self.didSetupSticker = true - self.disposable.set((sticker - |> deliverOnMainQueue).startStrict(next: { [weak self] sticker in - if let strongSelf = self, let sticker = sticker { - let inputNodeInteraction = ChatMediaInputNodeInteraction( - navigateToCollectionId: { _ in - }, - navigateBackToStickers: { - }, - setGifMode: { _ in - }, - openSettings: { - }, - openTrending: { _ in - }, - dismissTrendingPacks: { _ in - }, - toggleSearch: { _, _, _ in - }, - openPeerSpecificSettings: { - }, - dismissPeerSpecificSettings: { - }, - clearRecentlyUsedStickers: { - } - ) - inputNodeInteraction.displayStickerPlaceholder = false - - let index = ItemCollectionItemIndex(index: 0, id: 0) - let collectionId = ItemCollectionId(namespace: 0, id: 0) - let stickerPackItem = StickerPackItem(index: index, file: sticker, indexKeys: []) - let item = ChatMediaInputStickerGridItem(context: strongSelf.context, collectionId: collectionId, stickerPackInfo: nil, index: ItemCollectionViewEntryIndex(collectionIndex: 0, collectionId: collectionId, itemIndex: index), stickerItem: stickerPackItem, canManagePeerSpecificPack: nil, interfaceInteraction: nil, inputNodeInteraction: inputNodeInteraction, hasAccessory: false, theme: interfaceState.theme, large: true, selected: {}) - strongSelf.stickerItem = item - strongSelf.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true) - strongSelf.stickerNode.isVisibleInGrid = true - strongSelf.stickerNode.updateIsPanelVisible(true) - } - })) - } - - let insets = UIEdgeInsets(top: 15.0, left: 15.0, bottom: 15.0, right: 15.0) - let titleSpacing: CGFloat = 5.0 - let stickerSpacing: CGFloat = 5.0 - - var contentWidth: CGFloat = 210.0 - var contentHeight: CGFloat = 0.0 - - let titleSize = self.titleNode.updateLayout(CGSize(width: contentWidth, height: CGFloat.greatestFiniteMagnitude)) - let textSize = self.textNode.updateLayout(CGSize(width: contentWidth, height: CGFloat.greatestFiniteMagnitude)) - - contentWidth = max(contentWidth, max(titleSize.width, textSize.width)) - - contentHeight += titleSize.height + titleSpacing + textSize.height + stickerSpacing + stickerSize.height - - let contentRect = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: contentWidth, height: contentHeight)) - - let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - titleSize.width) / 2.0), y: contentRect.minY), size: titleSize) - transition.updateFrame(node: self.titleNode, frame: titleFrame) - - let textFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize) - transition.updateFrame(node: self.textNode, frame: textFrame) - - let stickerFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - stickerSize.width) / 2.0), y: textFrame.maxY + stickerSpacing), size: stickerSize) - transition.updateFrame(node: self.stickerNode, frame: stickerFrame) - - return contentRect.insetBy(dx: -insets.left, dy: -insets.top).size - } -} - private final class ChatEmptyNodeSecretChatContent: ASDisplayNode, ChatEmptyNodeContent { private let titleNode: ImmediateTextNode private let subtitleNode: ImmediateTextNode @@ -1461,7 +1290,6 @@ private enum ChatEmptyNodeContentType: Equatable { case secret case group case cloud - case peerNearby case greeting case topic case premiumRequired @@ -1851,8 +1679,6 @@ public final class ChatEmptyNode: ASDisplayNode { contentType = .group } else if let channel = peer as? TelegramChannel, case .group = channel.info, channel.flags.contains(.isCreator) && !channel.flags.contains(.isGigagroup) && !channel.isMonoForum { contentType = .group - } else if let _ = interfaceState.peerNearbyData { - contentType = .peerNearby } else if let peer = peer as? TelegramUser { if let sendPaidMessageStars = interfaceState.sendPaidMessageStars, interfaceState.businessIntro == nil { contentType = .starsRequired(sendPaidMessageStars.value) @@ -1917,8 +1743,6 @@ public final class ChatEmptyNode: ASDisplayNode { }) interfaceInteraction.presentControllerInCurrent(controller, nil) } - case .peerNearby: - node = ChatEmptyNodeNearbyChatContent(context: self.context, interaction: self.interaction) case .greeting: node = ChatEmptyNodeGreetingChatContent(context: self.context, interaction: self.interaction) updateGreetingSticker = true @@ -1939,7 +1763,7 @@ public final class ChatEmptyNode: ASDisplayNode { } } switch contentType { - case .peerNearby, .greeting, .premiumRequired, .starsRequired, .cloud: + case .greeting, .premiumRequired, .starsRequired, .cloud: self.isUserInteractionEnabled = true default: self.isUserInteractionEnabled = false diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift index 3baa7ab194..6506223629 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift @@ -487,7 +487,6 @@ public final class ChatTextInputPanelComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.chatPeerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, @@ -799,7 +798,6 @@ public final class ChatTextInputPanelComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.chatPeerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 8dc981dd44..92c25d9349 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -2711,7 +2711,6 @@ public final class EntityInputView: UIInputView, LegacyMessageInputPanelInputVie mode: .standard(.default), chatLocation: .peer(id: self.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift b/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift index 51d2bbf656..efac1db824 100644 --- a/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift +++ b/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift @@ -759,7 +759,6 @@ final class ComposePollScreenComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, @@ -771,8 +770,6 @@ final class ComposePollScreenComponent: Component { businessIntro: nil ) - //self.inputMediaNodeBackground.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor.cgColor - let heightAndOverflow = inputMediaNode.updateLayout(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, bottomInset: bottomInset, standardInputHeight: deviceMetrics.standardInputHeight(inLandscape: false), inputHeight: inputHeight < 100.0 ? inputHeight - bottomContainerInset : inputHeight, maximumHeight: availableSize.height, inputPanelHeight: 0.0, transition: .immediate, interfaceState: presentationInterfaceState, layoutMetrics: metrics, deviceMetrics: deviceMetrics, isVisible: true, isExpanded: false) let inputNodeHeight = heightAndOverflow.0 let inputNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - inputNodeHeight), size: CGSize(width: availableSize.width, height: inputNodeHeight)) diff --git a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift index eafa125640..d31acdf3c2 100644 --- a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift +++ b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift @@ -470,7 +470,6 @@ final class ComposeTodoScreenComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index 0cb8fe6662..840e88d024 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -767,7 +767,6 @@ private final class GiftSetupScreenComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, @@ -779,8 +778,6 @@ private final class GiftSetupScreenComponent: Component { businessIntro: nil ) - self.inputMediaNodeBackground.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor.cgColor - let heightAndOverflow = inputMediaNode.updateLayout(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, bottomInset: bottomInset, standardInputHeight: deviceMetrics.standardInputHeight(inLandscape: false), inputHeight: inputHeight < 100.0 ? inputHeight - bottomContainerInset : inputHeight, maximumHeight: availableSize.height, inputPanelHeight: 0.0, transition: .immediate, interfaceState: presentationInterfaceState, layoutMetrics: metrics, deviceMetrics: deviceMetrics, isVisible: true, isExpanded: false) let inputNodeHeight = heightAndOverflow.0 let inputNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - inputNodeHeight), size: CGSize(width: availableSize.width, height: inputNodeHeight)) diff --git a/submodules/TelegramUI/Components/LegacyMessageInputPanel/Sources/LegacyMessageInputPanel.swift b/submodules/TelegramUI/Components/LegacyMessageInputPanel/Sources/LegacyMessageInputPanel.swift index 0d4bad62c6..10605a67f4 100644 --- a/submodules/TelegramUI/Components/LegacyMessageInputPanel/Sources/LegacyMessageInputPanel.swift +++ b/submodules/TelegramUI/Components/LegacyMessageInputPanel/Sources/LegacyMessageInputPanel.swift @@ -521,7 +521,6 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView { mode: .standard(.default), chatLocation: .peer(id: self.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index 5602a7bcba..bf33c6725c 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -1257,7 +1257,6 @@ final class MediaEditorScreenComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index 46ff447e9f..aa830d9cec 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -1151,14 +1151,7 @@ func peerInfoScreenData( } else { groupsInCommon = nil } - - let recommendedBots: Signal - if case .bot = kind { - recommendedBots = context.engine.peers.recommendedBots(peerId: userPeerId) - } else { - recommendedBots = .single(nil) - } - + let premiumGiftOptions: Signal<[PremiumGiftCodeOption], NoError> let profileGiftsContext: ProfileGiftsContext? let profileGiftsCollectionsContext: ProfileGiftsCollectionsContext? @@ -1280,7 +1273,7 @@ func peerInfoScreenData( |> distinctUntilChanged var secretChatKeyFingerprint: Signal = .single(nil) - if let secretChatId = secretChatId { + if let secretChatId { secretChatKeyFingerprint = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.SecretChatKeyFingerprint(id: secretChatId)) } @@ -1310,21 +1303,7 @@ func peerInfoScreenData( } else { hasStoryArchive = .single(false) } - - var botPreviewStoryListContext: StoryListContext? - let hasBotPreviewItems: Signal - if case .bot = kind { - let botPreviewStoryListContextValue = BotPreviewStoryListContext(account: context.account, engine: context.engine, peerId: peerId, language: nil, assumeEmpty: false) - botPreviewStoryListContext = botPreviewStoryListContextValue - hasBotPreviewItems = botPreviewStoryListContextValue.state - |> map { state in - return !state.items.isEmpty - } - |> distinctUntilChanged - } else { - hasBotPreviewItems = .single(false) - } - + let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) |> map { peer -> Bool in return peer?.isPremium ?? false @@ -1407,64 +1386,88 @@ func peerInfoScreenData( hasSavedMessageTags = .single(false) } - let starsRevenueContextAndState = combineLatest( - context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) - |> distinctUntilChanged, - context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId)) - |> distinctUntilChanged - ) - |> mapToSignal { peer, canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in - var canViewStarsRevenue = canViewRevenue - if let peer, case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) || context.sharedContext.applicationBindings.appBuildType == .internal || context.sharedContext.immediateExperimentalUISettings.devRequests { - canViewStarsRevenue = true - } - #if DEBUG - canViewStarsRevenue = peerId != context.account.peerId - #endif + let recommendedBots: Signal + var botPreviewStoryListContext: StoryListContext? + let hasBotPreviewItems: Signal + let starsRevenueContextAndState: Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> + let revenueContextAndState: Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> + let webAppPermissions: Signal + if case .bot = kind { + recommendedBots = context.engine.peers.recommendedBots(peerId: userPeerId) - guard canViewStarsRevenue else { - return .single((nil, nil)) + let botPreviewStoryListContextValue = BotPreviewStoryListContext(account: context.account, engine: context.engine, peerId: peerId, language: nil, assumeEmpty: false) + botPreviewStoryListContext = botPreviewStoryListContextValue + hasBotPreviewItems = botPreviewStoryListContextValue.state + |> map { state in + return !state.items.isEmpty } - let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: false) - return starsRevenueStatsContext.state - |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in - return (starsRevenueStatsContext, state.stats) - } - } - - let revenueContextAndState = combineLatest( - context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) - |> distinctUntilChanged, - context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId)) |> distinctUntilChanged - ) - |> mapToSignal { peer, canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in - var canViewRevenue = canViewRevenue - if let peer, case let .user(user) = peer, let _ = user.botInfo, context.sharedContext.applicationBindings.appBuildType == .internal || context.sharedContext.immediateExperimentalUISettings.devRequests { - canViewRevenue = true + + starsRevenueContextAndState = combineLatest( + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> distinctUntilChanged, + context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId)) + |> distinctUntilChanged + ) + |> mapToSignal { peer, canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in + var canViewStarsRevenue = canViewRevenue + if let peer, case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) || context.sharedContext.applicationBindings.appBuildType == .internal || context.sharedContext.immediateExperimentalUISettings.devRequests { + canViewStarsRevenue = true + } + #if DEBUG + canViewStarsRevenue = peerId != context.account.peerId + #endif + + guard canViewStarsRevenue else { + return .single((nil, nil)) + } + let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: false) + return starsRevenueStatsContext.state + |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in + return (starsRevenueStatsContext, state.stats) + } } - #if DEBUG - canViewRevenue = peerId != context.account.peerId - #endif - guard canViewRevenue else { - return .single((nil, nil)) + + revenueContextAndState = combineLatest( + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> distinctUntilChanged, + context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId)) + |> distinctUntilChanged + ) + |> mapToSignal { peer, canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in + var canViewRevenue = canViewRevenue + if let peer, case let .user(user) = peer, let _ = user.botInfo, context.sharedContext.applicationBindings.appBuildType == .internal || context.sharedContext.immediateExperimentalUISettings.devRequests { + canViewRevenue = true + } + #if DEBUG + canViewRevenue = peerId != context.account.peerId + #endif + guard canViewRevenue else { + return .single((nil, nil)) + } + let revenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: true) + return revenueStatsContext.state + |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in + return (revenueStatsContext, state.stats) + } } - let revenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: true) - return revenueStatsContext.state - |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in - return (revenueStatsContext, state.stats) + + webAppPermissions = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> mapToSignal { peer -> Signal in + if let peer, case let .user(user) = peer, let _ = user.botInfo { + return webAppPermissionsState(context: context, peerId: peerId) + } else { + return .single(nil) + } } + } else { + recommendedBots = .single(nil) + hasBotPreviewItems = .single(false) + starsRevenueContextAndState = .single((nil, nil)) + revenueContextAndState = .single((nil, nil)) + webAppPermissions = .single(nil) } - - let webAppPermissions: Signal = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) - |> mapToSignal { peer -> Signal in - if let peer, case let .user(user) = peer, let _ = user.botInfo { - return webAppPermissionsState(context: context, peerId: peerId) - } else { - return .single(nil) - } - } - + let savedMusicContext = ProfileSavedMusicContext(account: context.account, peerId: peerId) let businessConnectedBot: Signal diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoProfileItems.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoProfileItems.swift index d24b90a11c..7005e4ccf9 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoProfileItems.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoProfileItems.swift @@ -36,7 +36,17 @@ enum InfoSection: Int, CaseIterable { case botAffiliateProgram } -func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], chatLocation: ChatLocation, isOpenedFromChat: Bool, isMyProfile: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] { +func infoItems( + data: PeerInfoScreenData?, + context: AccountContext, + presentationData: PresentationData, + interaction: PeerInfoInteraction, + reactionSourceMessageId: MessageId?, + callMessages: [Message], + chatLocation: ChatLocation, + isOpenedFromChat: Bool, + isMyProfile: Bool +) -> [(AnyHashable, [PeerInfoScreenItem])] { guard let data = data else { return [] } @@ -367,14 +377,6 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: ItemReport, text: presentationData.strings.ReportPeer_BanAndReport, color: .destructive, action: { interaction.openReport(.reaction(reactionSourceMessageId)) })) - } else if let _ = nearbyPeerDistance { - items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: ItemSendMessage, text: presentationData.strings.UserInfo_SendMessage, action: { - interaction.openChat(nil) - })) - - items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: ItemReport, text: presentationData.strings.ReportPeer_Report, color: .destructive, action: { - interaction.openReport(.user) - })) } else { if !data.isContact { if user.botInfo == nil { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 40e9900476..09f764b071 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -281,8 +281,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro personalChannels: nil ) var forceIsContactPromise = ValuePromise(false) - let nearbyPeerDistance: Int32? let reactionSourceMessageId: MessageId? + let sourceMessageId: MessageId? var dataDisposable: Disposable? let activeActionDisposable = MetaDisposable() @@ -347,15 +347,38 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private var didSetReady = false - init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, switchToStoryFolder: Int64?, switchToMediaTarget: PeerInfoSwitchToMediaTarget?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) { + init( + controller: PeerInfoScreenImpl, + context: AccountContext, + peerId: PeerId, + avatarInitiallyExpanded: Bool, + isOpenedFromChat: Bool, + reactionSourceMessageId: MessageId?, + sourceMessageId: MessageId?, + callMessages: [Message], + isSettings: Bool, + isMyProfile: Bool, + hintGroupInCommon: PeerId?, + requestsContext: PeerInvitationImportersContext?, + profileGiftsContext: ProfileGiftsContext?, + starsContext: StarsContext?, + tonContext: StarsContext?, + chatLocation: ChatLocation, + chatLocationContextHolder: Atomic, + switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, + switchToStoryFolder: Int64?, + switchToMediaTarget: PeerInfoSwitchToMediaTarget?, + initialPaneKey: PeerInfoPaneKey?, + sharedMediaFromForumTopic: (EnginePeer.Id, Int64)? + ) { self.controller = controller self.context = context self.peerId = peerId self.isOpenedFromChat = isOpenedFromChat self.videoCallsEnabled = true self.presentationData = controller.presentationData - self.nearbyPeerDistance = nearbyPeerDistance self.reactionSourceMessageId = reactionSourceMessageId + self.sourceMessageId = sourceMessageId self.callMessages = callMessages self.isSettings = isSettings self.isMyProfile = isMyProfile @@ -2322,7 +2345,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] c, f in if let strongSelf = self, let parent = strongSelf.controller { - presentPeerReportOptions(context: context, parent: parent, contextController: c, subject: .profilePhoto(peer.id, 0), completion: { _, _ in }) + presentPeerReportOptions(context: context, parent: parent, contextController: c, subject: .profilePhoto(peer.id, 0, sourceMessageId: strongSelf.sourceMessageId), completion: { _, _ in }) } })) ] @@ -2479,12 +2502,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro strongSelf.cachedDataPromise.set(.single(data.cachedData)) }) - if let _ = nearbyPeerDistance { - self.preloadHistoryDisposable.set(self.context.account.addAdditionalPreloadHistoryPeerId(peerId: peerId)) - - self.context.prefetchManager?.prepareNextGreetingSticker() - } - self.customStatusDisposable = (self.customStatusPromise.get() |> deliverOnMainQueue).startStrict(next: { [weak self] value in guard let strongSelf = self else { @@ -3435,7 +3452,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro let presentationData = strongSelf.presentationData if case let .user(peer) = peer, let _ = peer.botInfo { - strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: block).startStrict()) + strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: block, sourceMessageId: strongSelf.sourceMessageId).startStrict()) if !block { let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: "/start", attributes: [], inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).startStandalone() if let navigationController = strongSelf.controller?.navigationController as? NavigationController { @@ -3460,12 +3477,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro return } - strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: true).startStrict()) + strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: true, sourceMessageId: strongSelf.sourceMessageId).startStrict()) if deleteChat { let _ = strongSelf.context.engine.peers.removePeerChat(peerId: strongSelf.peerId, reportChatSpam: reportSpam).startStandalone() (strongSelf.controller?.navigationController as? NavigationController)?.popToRoot(animated: true) } else if reportSpam { - let _ = strongSelf.context.engine.peers.reportPeer(peerId: strongSelf.peerId, reason: .spam, message: "").startStandalone() + let _ = strongSelf.context.engine.peers.reportPeer(peerId: strongSelf.peerId, reason: .spam, message: "", sourceMessageId: strongSelf.sourceMessageId).startStandalone() } deleteSendMessageIntents(peerId: strongSelf.peerId) @@ -3486,7 +3503,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro guard let strongSelf = self else { return } - strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: block).startStrict()) + strongSelf.activeActionDisposable.set(strongSelf.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: peer.id, isBlocked: block, sourceMessageId: strongSelf.sourceMessageId).startStrict()) })]), in: .window(.root)) } } @@ -3567,7 +3584,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro guard let self else { return } - self.activeActionDisposable.set(self.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: self.peerId, isBlocked: true).startStrict()) + self.activeActionDisposable.set(self.context.engine.privacy.requestUpdatePeerIsBlocked(peerId: self.peerId, isBlocked: true, sourceMessageId: sourceMessageId).startStrict()) self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .emoji(name: "PoliceCar", text: self.presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current) }), ActionSheetButtonItem(title: presentationData.strings.ReportPeer_ReportReaction_Report, action: { [weak self] in @@ -3590,7 +3607,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro default: contextController?.dismiss() - self.context.sharedContext.makeContentReportScreen(context: self.context, subject: .peer(self.peerId), forceDark: false, present: { [weak self] controller in + let reportSubject = ReportContentSubject.peer(self.peerId, sourceMessageId: self.sourceMessageId) + self.context.sharedContext.makeContentReportScreen(context: self.context, subject: reportSubject, forceDark: false, present: { [weak self] controller in self?.controller?.push(controller) }, completion: { }, requestSelectMessages: { [weak self] title, option, message in @@ -4277,10 +4295,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func openPeerInfo(peer: Peer, isMember: Bool) { - var mode: PeerInfoControllerMode = .generic - if isMember { - mode = .group(self.peerId) - } + let mode: PeerInfoControllerMode = .generic if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: nil, peer: peer, mode: mode, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) { (self.controller?.navigationController as? NavigationController)?.pushViewController(infoController) } @@ -5187,7 +5202,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro scrollToEndIfExists: false, activateMessageSearch: nil, peekData: nil, - peerNearbyData: nil, reportReason: nil, animated: true, options: [], @@ -5393,7 +5407,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro insets.left += sectionInset insets.right += sectionInset - let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, chatLocation: self.chatLocation, isOpenedFromChat: self.isOpenedFromChat, isMyProfile: self.isMyProfile) + let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, chatLocation: self.chatLocation, isOpenedFromChat: self.isOpenedFromChat, isMyProfile: self.isMyProfile) contentHeight += headerHeight if !((self.isSettings || self.isMyProfile) && self.state.isEditing) { @@ -6305,8 +6319,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc public let peerId: PeerId private let avatarInitiallyExpanded: Bool private let isOpenedFromChat: Bool - private let nearbyPeerDistance: Int32? private let reactionSourceMessageId: MessageId? + private let sourceMessageId: MessageId? private let callMessages: [Message] let isSettings: Bool let isMyProfile: Bool @@ -6393,8 +6407,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, - nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, + sourceMessageId: MessageId? = nil, callMessages: [Message], isSettings: Bool = false, isMyProfile: Bool = false, @@ -6414,8 +6428,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc self.peerId = peerId self.avatarInitiallyExpanded = avatarInitiallyExpanded self.isOpenedFromChat = isOpenedFromChat - self.nearbyPeerDistance = nearbyPeerDistance self.reactionSourceMessageId = reactionSourceMessageId + self.sourceMessageId = sourceMessageId self.callMessages = callMessages self.isSettings = isSettings self.isMyProfile = isMyProfile @@ -6783,7 +6797,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc initialPaneKey = .files } } - self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, switchToMediaTarget: self.switchToMediaTarget, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic) + self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, reactionSourceMessageId: self.reactionSourceMessageId, sourceMessageId: self.sourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, switchToMediaTarget: self.switchToMediaTarget, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic) self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 }) self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get()) self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get()) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenOpenChat.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenOpenChat.swift index 824bd0ce0b..a886e7074c 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenOpenChat.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenOpenChat.swift @@ -22,18 +22,7 @@ extension PeerInfoScreenNode { navigationController.setViewControllers(viewControllers, animated: true) current.activateSearch(domain: .everything, query: "") } else if let peer = self.data?.chatPeer { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, activateMessageSearch: (.everything, ""), peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in - if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { - var viewControllers = navigationController.viewControllers - viewControllers = viewControllers.filter { controller in - if controller is PeerInfoScreen { - return false - } - return true - } - navigationController.setViewControllers(viewControllers, animated: false) - } - })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, activateMessageSearch: (.everything, ""))) } } } @@ -50,9 +39,7 @@ extension PeerInfoScreenNode { context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, - reportReason: NavigateToChatControllerParams.ReportReason(title: title, option: option, message: message), - completion: { _ in - } + reportReason: NavigateToChatControllerParams.ReportReason(title: title, option: option, message: message) ) ) } @@ -61,15 +48,13 @@ extension PeerInfoScreenNode { func openChatForThemeChange() { if let peer = self.data?.peer, let navigationController = (self.controller?.navigationController as? NavigationController) { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, changeColors: true, completion: { _ in - })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, changeColors: true)) } } func openChatForTranslation() { if let peer = self.data?.peer, let navigationController = (self.controller?.navigationController as? NavigationController) { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, changeColors: false, completion: { _ in - })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, changeColors: false)) } } @@ -92,18 +77,7 @@ extension PeerInfoScreenNode { } if let peer = self.data?.peer, let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in - if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { - var viewControllers = navigationController.viewControllers - viewControllers = viewControllers.filter { controller in - if controller is PeerInfoScreen { - return false - } - return true - } - navigationController.setViewControllers(viewControllers, animated: false) - } - })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default)) } } @@ -112,20 +86,8 @@ extension PeerInfoScreenNode { return } - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), setupController: { controller in + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, setupController: { controller in controller.beginClearHistory(type: type) - }, completion: { [weak self] _ in - if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { - var viewControllers = navigationController.viewControllers - viewControllers = viewControllers.filter { controller in - if controller is PeerInfoScreen { - return false - } - return true - } - - navigationController.setViewControllers(viewControllers, animated: false) - } })) } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenPerformButtonAction.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenPerformButtonAction.swift index d5f1c3f837..903e2128a4 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenPerformButtonAction.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenPerformButtonAction.swift @@ -35,18 +35,7 @@ extension PeerInfoScreenNode { self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), keepStack: .default)) } } else { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in - if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { - var viewControllers = navigationController.viewControllers - viewControllers = viewControllers.filter { controller in - if controller is PeerInfoScreen { - return false - } - return true - } - navigationController.setViewControllers(viewControllers, animated: false) - } - })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default)) } } case .discussion: @@ -812,7 +801,7 @@ extension PeerInfoScreenNode { } let _ = self.context.engine.peers.toggleMessageCopyProtection(peerId: user.id, enabled: true).start() - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, peerNearbyData: nil, completion: { _ in })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .default, completion: { _ in })) } let _ = (ApplicationSpecificNotice.getCopyProtectionTips(accountManager: self.context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { [weak self] count in diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenSettingsActions.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenSettingsActions.swift index 0e64cec1d7..3376571fec 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenSettingsActions.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenSettingsActions.swift @@ -58,7 +58,6 @@ extension PeerInfoScreenNode { peerId: self.context.account.peerId, avatarInitiallyExpanded: false, isOpenedFromChat: false, - nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], isMyProfile: true, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift index a07cfeaf60..97065b90f1 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift @@ -198,7 +198,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor - let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, preferredGlassType: .default, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) + let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, preferredGlassType: .default, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: self.peerId), subject: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height, maxOverlayHeight: layout.size.height, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: false) transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeight))) diff --git a/submodules/TelegramUI/Components/PeerReportScreen/Sources/PeerReportScreen.swift b/submodules/TelegramUI/Components/PeerReportScreen/Sources/PeerReportScreen.swift index cdae86c7b0..d4cef5ddbe 100644 --- a/submodules/TelegramUI/Components/PeerReportScreen/Sources/PeerReportScreen.swift +++ b/submodules/TelegramUI/Components/PeerReportScreen/Sources/PeerReportScreen.swift @@ -18,7 +18,7 @@ import Markdown public enum PeerReportSubject { case peer(EnginePeer.Id) case messages([EngineMessage.Id]) - case profilePhoto(EnginePeer.Id, Int64) + case profilePhoto(EnginePeer.Id, Int64, sourceMessageId: EngineMessage.Id?) case story(EnginePeer.Id, Int32) } @@ -149,8 +149,8 @@ public func presentPeerReportOptions( displaySuccess() completion(nil, false) }) - case let .profilePhoto(peerId, _): - let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: "") + case let .profilePhoto(peerId, _, sourceMessageId): + let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: "", sourceMessageId: sourceMessageId) |> deliverOnMainQueue).start(completed: { displaySuccess() completion(nil, false) @@ -285,8 +285,8 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe displaySuccess() completion(nil, true) }) - case let .profilePhoto(peerId, _): - let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: message) + case let .profilePhoto(peerId, _, sourceMessageId): + let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: message, sourceMessageId: sourceMessageId) |> deliverOnMainQueue).start(completed: { displaySuccess() completion(nil, true) diff --git a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift index bce7809348..b8a5d099e5 100644 --- a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift @@ -135,7 +135,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { self.animationCache = context.animationCache self.animationRenderer = context.animationRenderer - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: PeerId(0)), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: PeerId(0)), subject: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(forwardedMessageIds) } self.presentationInterfaceStatePromise.set(self.presentationInterfaceState) diff --git a/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/ChatIntroItemComponent.swift b/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/ChatIntroItemComponent.swift index e1a568e5da..0674297168 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/ChatIntroItemComponent.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/ChatIntroItemComponent.swift @@ -122,7 +122,6 @@ final class ChatIntroItemComponent: Component { mode: .standard(.default), chatLocation: .peer(id: component.context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 90a57d5a3e..b75c45b5c1 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -357,7 +357,6 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { mode: .standard(.default), chatLocation: .peer(id: context.account.peerId), subject: nil, - peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, @@ -2541,7 +2540,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) { let fileId = Int64.random(in: Int64.min ... Int64.max) let mimeType = guessMimeTypeByFileExtension((item.fileName as NSString).pathExtension) var previewRepresentations: [TelegramMediaImageRepresentation] = [] - if mimeType.hasPrefix("image/") || mimeType == "application/pdf" { + if mimeType.hasPrefix("image/") || mimeType == "application/pdf" || item.audioMetadata?.hasAudioArtwork == true { previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 320, height: 320), resource: ICloudFileResource(urlData: item.urlData, thumbnail: true), progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) } var attributes: [TelegramMediaFileAttribute] = [] diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift index d4e0f3fca8..b37a317b7d 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift @@ -184,8 +184,8 @@ extension ChatControllerImpl { self.navigationActionDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).startStrict(next: { [weak self] peer in if let strongSelf = self, let peer = peer { var mode: PeerInfoControllerMode = .generic - if let _ = fromMessage, let chatPeerId = chatPeerId { - mode = .group(chatPeerId) + if let messageId = fromMessage?.id, chatPeerId != nil { + mode = .group(sourceMessageId: messageId) } if let fromReactionMessageId = fromReactionMessageId { mode = .reaction(fromReactionMessageId) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 0efc6cbbe2..4ce1e0e53c 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -638,7 +638,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G botAppStart: ChatControllerInitialBotAppStart? = nil, mode: ChatControllerPresentationMode = .standard(.default), peekData: ChatPeekTimeout? = nil, - peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], customChatNavigationStack: [EnginePeer.Id]? = nil, @@ -689,7 +688,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.stickerSettings = ChatInterfaceStickerSettings() - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation, subject: subject, peerNearbyData: peerNearbyData, greetingData: context.prefetchManager?.preloadedGreetingSticker, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation, subject: subject, greetingData: context.prefetchManager?.preloadedGreetingSticker, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) if case let .customChatContents(customChatContents) = subject { switch customChatContents.kind { diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift index f3bb5fba6b..cdbc6e1c45 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift @@ -1257,7 +1257,7 @@ extension ChatControllerImpl { let fileId = Int64.random(in: Int64.min ... Int64.max) let mimeType = guessMimeTypeByFileExtension((item.fileName as NSString).pathExtension) var previewRepresentations: [TelegramMediaImageRepresentation] = [] - if mimeType.hasPrefix("image/") || mimeType == "application/pdf" { + if mimeType.hasPrefix("image/") || mimeType == "application/pdf" || item.audioMetadata?.hasAudioArtwork == true { previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 320, height: 320), resource: ICloudFileResource(urlData: item.urlData, thumbnail: true), progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) } var attributes: [TelegramMediaFileAttribute] = [] diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index 74ca2b1aa1..1e1053453d 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -253,7 +253,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam } } } else { - controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack, customChatNavigationStack: params.customChatNavigationStack) + controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack, customChatNavigationStack: params.customChatNavigationStack) if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation { Queue.mainQueue().after(0.1) { diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift index 6f01d7b03a..ed034ebced 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift @@ -180,7 +180,7 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer let fileId = Int64.random(in: Int64.min ... Int64.max) let mimeType = guessMimeTypeByFileExtension((item.fileName as NSString).pathExtension) var previewRepresentations: [TelegramMediaImageRepresentation] = [] - if mimeType.hasPrefix("image/") || mimeType == "application/pdf" { + if mimeType.hasPrefix("image/") || mimeType == "application/pdf" || item.audioMetadata?.hasAudioArtwork == true { previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 320, height: 320), resource: ICloudFileResource(urlData: item.urlData, thumbnail: true), progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) } var attributes: [TelegramMediaFileAttribute] = [] diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 4e98f7899b..a8fc4c1c50 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -4448,14 +4448,17 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation } if let _ = peer as? TelegramGroup { - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) } else if let _ = peer as? TelegramChannel { + var sourceMessageId: MessageId? var forumTopicThread: ChatReplyThreadMessage? var switchToRecommendedChannels = false var switchToGiftsTarget: PeerInfoSwitchToGiftsTarget? var switchToGroupsInCommon = false var switchToStoryFolder: Int64? switch mode { + case let .group(messageId): + sourceMessageId = messageId case let .forumTopic(thread): forumTopicThread = thread case .recommendedChannels: @@ -4471,10 +4474,10 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation default: break } - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], forumTopicThread: forumTopicThread, switchToRecommendedChannels: switchToRecommendedChannels, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, reactionSourceMessageId: nil, sourceMessageId: sourceMessageId, callMessages: [], forumTopicThread: forumTopicThread, switchToRecommendedChannels: switchToRecommendedChannels, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) } else if peer is TelegramUser { - var nearbyPeerDistance: Int32? var reactionSourceMessageId: MessageId? + var sourceMessageId: MessageId? var callMessages: [Message] = [] var hintGroupInCommon: PeerId? var forumTopicThread: ChatReplyThreadMessage? @@ -4485,16 +4488,16 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation var switchToStoryFolder: Int64? switch mode { - case let .nearbyPeer(distance): - nearbyPeerDistance = distance case let .calls(messages): callMessages = messages case .generic: break - case let .group(id): - hintGroupInCommon = id + case let .group(messageId): + hintGroupInCommon = messageId.peerId + sourceMessageId = messageId case let .reaction(messageId): reactionSourceMessageId = messageId + sourceMessageId = messageId case let .forumTopic(thread): forumTopicThread = thread case .myProfile: @@ -4524,9 +4527,9 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation default: break } - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, reactionSourceMessageId: reactionSourceMessageId, sourceMessageId: sourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) } else if peer is TelegramSecretChat { - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) } return nil } diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 11cdee3266..db5f613c5c 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -41,7 +41,7 @@ private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceh init(context: AccountContext) { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: .default, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: context.account.peerId), subject: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) self.wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: true) self.emptyNode = ChatEmptyNode(context: context, interaction: nil) @@ -55,7 +55,7 @@ private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceh func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData let preferredGlassType = self.presentationInterfaceState.preferredGlassType - self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: preferredGlassType, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.presentationInterfaceState.limitsConfiguration, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.presentationInterfaceState.accountPeerId, mode: .standard(.default), chatLocation: self.presentationInterfaceState.chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) + self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, preferredGlassType: preferredGlassType, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.presentationInterfaceState.limitsConfiguration, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.presentationInterfaceState.accountPeerId, mode: .standard(.default), chatLocation: self.presentationInterfaceState.chatLocation, subject: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) self.wallpaperBackgroundNode.update(wallpaper: presentationData.chatWallpaper, animated: false) } @@ -230,7 +230,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon sharedContext.switchingData = (nil, nil, nil) } - let accountSettingsController = PeerInfoScreenImpl(context: self.context, updatedPresentationData: nil, peerId: self.context.account.peerId, avatarInitiallyExpanded: false, isOpenedFromChat: false, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], isSettings: true) + let accountSettingsController = PeerInfoScreenImpl(context: self.context, updatedPresentationData: nil, peerId: self.context.account.peerId, avatarInitiallyExpanded: false, isOpenedFromChat: false, reactionSourceMessageId: nil, callMessages: [], isSettings: true) accountSettingsController.tabBarItemDebugTapAction = { [weak self] in guard let strongSelf = self else { return