diff --git a/submodules/Postbox/Sources/MessageHistoryTable.swift b/submodules/Postbox/Sources/MessageHistoryTable.swift index 4f800747b7..017907b553 100644 --- a/submodules/Postbox/Sources/MessageHistoryTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTable.swift @@ -2616,11 +2616,11 @@ final class MessageHistoryTable: Table { } } - #if DEBUG + /*#if DEBUG for key in associatedStories.keys { associatedStories[key] = CodableEntry(data: Data()) } - #endif + #endif*/ associatedMessageIds.append(contentsOf: attribute.associatedMessageIds) if addAssociatedMessages { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift index 695d126d29..4ae1ef2818 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift @@ -99,8 +99,7 @@ final class MediaNavigationStripComponent: Component { var validIndices: [Int] = [] if component.count != 0 { - var idealItemWidth: CGFloat = (availableSize.width - CGFloat(component.count - 1) * spacing) / CGFloat(component.count) - idealItemWidth = floor(idealItemWidth) + let idealItemWidth: CGFloat = (availableSize.width - CGFloat(component.count - 1) * spacing) / CGFloat(component.count) let itemWidth: CGFloat if idealItemWidth < minItemWidth { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift index 3f574d0588..20d470ea56 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift @@ -562,12 +562,16 @@ public final class StoryContentContextImpl: StoryContentContext { var sortedItems: [EngineStorySubscriptions.Item] = [] if let accountItem = storySubscriptions.accountItem { - if startedWithUnseen { - if accountItem.hasUnseen || accountItem.hasPending { + if self.fixedSubscriptionOrder.contains(context.account.peerId) { + sortedItems.append(accountItem) + } else { + if startedWithUnseen { + if accountItem.hasUnseen || accountItem.hasPending { + sortedItems.append(accountItem) + } + } else { sortedItems.append(accountItem) } - } else { - sortedItems.append(accountItem) } } for peerId in self.fixedSubscriptionOrder { diff --git a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListItemComponent.swift b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListItemComponent.swift index f594019265..2524672c31 100644 --- a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListItemComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListItemComponent.swift @@ -464,6 +464,7 @@ public final class StoryPeerListItemComponent: Component { } component.contextGesture(self.extractedContainerNode, gesture, component.peer) } + self.containerNode.additionalActivationProgressLayer = self.avatarBackgroundContainer.layer self.extractedContainerNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtracted, transition in guard let self, let component = self.component else { @@ -545,8 +546,6 @@ public final class StoryPeerListItemComponent: Component { } self.avatarBackgroundView.image = avatarBackgroundImage - self.avatarBackgroundView.isHidden = component.ringAnimation != nil - if themeUpdated { self.avatarBackgroundView.tintColor = component.theme.rootController.navigationBar.opaqueBackgroundColor } @@ -625,7 +624,7 @@ public final class StoryPeerListItemComponent: Component { } avatarAddBadgeTransition.setFrame(view: avatarAddBadgeView, frame: CGRect(origin: CGPoint(x: avatarFrame.width - 1.0 - badgeSize.width, y: avatarFrame.height - 2.0 - badgeSize.height), size: badgeSize)) } else { - if indicatorColorLayer.isHidden { + if self.indicatorColorLayer.isHidden { self.indicatorColorLayer.isHidden = false } @@ -635,6 +634,8 @@ public final class StoryPeerListItemComponent: Component { } } + self.avatarBackgroundView.isHidden = component.ringAnimation != nil || self.indicatorColorLayer.isHidden + let baseRadius: CGFloat = 30.0 let collapsedRadius: CGFloat = 32.0 let indicatorRadius: CGFloat = baseRadius * component.scale + collapsedRadius * (1.0 - component.scale) diff --git a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift index b3fc60d7ae..809f4a24f3 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift @@ -41,6 +41,7 @@ struct ChatMessageAttachedContentNodeMediaFlags: OptionSet { static let preferMediaInline = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 0) static let preferMediaBeforeText = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 1) static let preferMediaAspectFilled = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 2) + static let titleBeforeMedia = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 3) } final class ChatMessageAttachedContentButtonNode: HighlightTrackingButtonNode { @@ -261,6 +262,7 @@ final class ChatMessageAttachedContentButtonNode: HighlightTrackingButtonNode { final class ChatMessageAttachedContentNode: ASDisplayNode { private let lineNode: ASImageNode + private let topTitleNode: TextNode private let textNode: TextNodeWithEntities private let inlineImageNode: TransformImageNode private var contentImageNode: ChatMessageInteractiveMediaNode? @@ -306,6 +308,12 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { self.lineNode.displaysAsynchronously = false self.lineNode.displayWithoutProcessing = true + self.topTitleNode = TextNode() + self.topTitleNode.isUserInteractionEnabled = false + self.topTitleNode.displaysAsynchronously = false + self.topTitleNode.contentsScale = UIScreenScale + self.topTitleNode.contentMode = .topLeft + self.textNode = TextNodeWithEntities() self.textNode.textNode.isUserInteractionEnabled = false self.textNode.textNode.displaysAsynchronously = false @@ -322,12 +330,14 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { super.init() self.addSubnode(self.lineNode) + self.addSubnode(self.topTitleNode) self.addSubnode(self.textNode.textNode) self.addSubnode(self.statusNode) } func asyncLayout() -> (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ chatLocation: ChatLocation, _ title: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ constrainedSize: CGSize, _ animationCache: AnimationCache, _ animationRenderer: MultiAnimationRenderer) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { + let topTitleAsyncLayout = TextNode.asyncLayout(self.topTitleNode) let textAsyncLayout = TextNodeWithEntities.asyncLayout(self.textNode) let currentImage = self.media as? TelegramMediaImage let imageLayout = self.inlineImageNode.asyncLayout() @@ -367,11 +377,13 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { horizontalInsets.left += 12.0 } + var titleBeforeMedia = false var preferMediaBeforeText = false var preferMediaAspectFilled = false if let (_, flags) = mediaAndFlags { preferMediaBeforeText = flags.contains(.preferMediaBeforeText) preferMediaAspectFilled = flags.contains(.preferMediaAspectFilled) + titleBeforeMedia = flags.contains(.titleBeforeMedia) } var contentMode: InteractiveMediaNodeContentMode = preferMediaAspectFilled ? .aspectFill : .aspectFit @@ -428,14 +440,20 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { var contentInstantVideoSizeAndApply: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> ChatMessageInteractiveInstantVideoNode)? + let topTitleString = NSMutableAttributedString() + let string = NSMutableAttributedString() var notEmpty = false let messageTheme = incoming ? presentationData.theme.theme.chat.message.incoming : presentationData.theme.theme.chat.message.outgoing if let title = title, !title.isEmpty { - string.append(NSAttributedString(string: title, font: titleFont, textColor: messageTheme.accentTextColor)) - notEmpty = true + if titleBeforeMedia { + topTitleString.append(NSAttributedString(string: title, font: titleFont, textColor: messageTheme.accentTextColor)) + } else { + string.append(NSAttributedString(string: title, font: titleFont, textColor: messageTheme.accentTextColor)) + notEmpty = true + } } if let subtitle = subtitle, subtitle.length > 0 { @@ -724,6 +742,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { let upatedTextCutout = textCutout + + let (topTitleLayout, topTitleApply) = topTitleAsyncLayout(TextNodeLayoutArguments(attributedString: topTitleString, backgroundColor: nil, maximumNumberOfLines: 12, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = textAsyncLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 12, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: upatedTextCutout, insets: UIEdgeInsets())) var statusSuggestedWidthAndContinue: (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))? @@ -765,6 +785,11 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { var boundingSize = textFrame.size var lineHeight = textLayout.rawTextSize.height + if titleBeforeMedia { + lineHeight += topTitleLayout.size.height + 4.0 + boundingSize.height += topTitleLayout.size.height + 4.0 + boundingSize.width = max(boundingSize.width, topTitleLayout.size.width) + } if let inlineImageSize = inlineImageSize { if boundingSize.height < inlineImageSize.height { boundingSize.height = inlineImageSize.height @@ -946,8 +971,11 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { } var textVerticalOffset: CGFloat = 0.0 + if titleBeforeMedia { + textVerticalOffset += topTitleLayout.size.height + 4.0 + } if let contentMediaHeight = contentMediaHeight, let (_, flags) = mediaAndFlags, flags.contains(.preferMediaBeforeText) { - textVerticalOffset = contentMediaHeight + 7.0 + textVerticalOffset += contentMediaHeight + 7.0 } let adjustedTextFrame = textFrame.offsetBy(dx: 0.0, dy: textVerticalOffset) @@ -981,6 +1009,9 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { strongSelf.textNode.textNode.displaysAsynchronously = !isPreview + let _ = topTitleApply() + strongSelf.topTitleNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: insets.top), size: topTitleLayout.size) + let _ = textApply(TextNodeWithEntities.Arguments( context: context, cache: animationCache, @@ -1036,9 +1067,12 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { contentImageNode.visibility = strongSelf.visibility != .none } let _ = contentImageApply(animation, synchronousLoads) - let contentImageFrame: CGRect + var contentImageFrame: CGRect if let (_, flags) = mediaAndFlags, flags.contains(.preferMediaBeforeText) { contentImageFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: contentImageSize) + if titleBeforeMedia { + contentImageFrame.origin.y += topTitleLayout.size.height + 4.0 + } } else { contentImageFrame = CGRect(origin: CGPoint(x: insets.left, y: textFrame.maxY + (textFrame.size.height > CGFloat.ulpOfOne ? 4.0 : 0.0)), size: contentImageSize) } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index 6d683c4aee..00d6a6e485 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -702,9 +702,15 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio var maxHeight = layoutConstants.image.maxDimensions.height var isStory = false + var additionalWidthConstrainment = false var unboundSize: CGSize if let _ = media as? TelegramMediaStory { - unboundSize = CGSize(width: 1080, height: 1920) + if message.media.contains(where: { $0 is TelegramMediaWebpage }) { + additionalWidthConstrainment = true + unboundSize = CGSize(width: 174.0, height: 239.0) + } else { + unboundSize = CGSize(width: 1080, height: 1920) + } } else if let image = media as? TelegramMediaImage, let dimensions = largestImageRepresentation(image.representations)?.dimensions { unboundSize = CGSize(width: max(10.0, floor(dimensions.cgSize.width * 0.5)), height: max(10.0, floor(dimensions.cgSize.height * 0.5))) } else if let file = media as? TelegramMediaFile, var dimensions = file.dimensions { @@ -806,7 +812,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio if isSticker { nativeSize = unboundSize.aspectFittedOrSmaller(constrainedSize) } else { - if unboundSize.width > unboundSize.height { + var constrainedSize = constrainedSize + if additionalWidthConstrainment { + constrainedSize.width = min(constrainedSize.width, unboundSize.width) + constrainedSize.height = min(constrainedSize.height, unboundSize.height) + } + if unboundSize.width > unboundSize.height || additionalWidthConstrainment { nativeSize = unboundSize.aspectFitted(constrainedSize) } else { nativeSize = unboundSize.aspectFitted(CGSize(width: constrainedSize.height, height: constrainedSize.width)) @@ -867,7 +878,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio if isSecretMedia { resultWidth = maxWidth } else { - let maxFittedSize = nativeSize.aspectFitted(maxDimensions) + let maxFittedSize: CGSize + if additionalWidthConstrainment { + maxFittedSize = nativeSize.aspectFittedOrSmaller(maxDimensions) + } else { + maxFittedSize = nativeSize.aspectFitted(maxDimensions) + } resultWidth = min(nativeSize.width, min(maxFittedSize.width, min(constrainedSize.width, maxDimensions.width))) resultWidth = max(resultWidth, layoutConstants.image.minDimensions.width) } @@ -886,7 +902,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio drawingSize = nativeSize.aspectFilled(boundingSize) } else { let fittedSize = nativeSize.fittedToWidthOrSmaller(boundingWidth) - let filledSize = fittedSize.aspectFilled(CGSize(width: boundingWidth, height: fittedSize.height)) + let filledSize: CGSize + if additionalWidthConstrainment { + filledSize = fittedSize + } else { + filledSize = fittedSize.aspectFilled(CGSize(width: boundingWidth, height: fittedSize.height)) + } boundingSize = CGSize(width: boundingWidth, height: filledSize.height).cropped(CGSize(width: CGFloat.greatestFiniteMagnitude, height: maxHeight)) boundingSize.height = max(boundingSize.height, layoutConstants.image.minDimensions.height) diff --git a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift index b1a02b4f41..02e1c4b8a7 100644 --- a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -221,7 +221,11 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode { mediaAndFlags = (image, flags) } } else if let story = mainMedia as? TelegramMediaStory { - mediaAndFlags = (story, []) + mediaAndFlags = (story, [.preferMediaBeforeText, .titleBeforeMedia]) + if let storyItem = item.message.associatedStories[story.storyId]?.get(Stories.StoredItem.self), case let .item(itemValue) = storyItem { + text = itemValue.text + entities = itemValue.entities + } } else if let type = webpage.type { if type == "telegram_background" { var colors: [UInt32] = []