mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Stories
This commit is contained in:
parent
fa52c23399
commit
fa3e626f47
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -562,6 +562,9 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
|
||||
var sortedItems: [EngineStorySubscriptions.Item] = []
|
||||
if let accountItem = storySubscriptions.accountItem {
|
||||
if self.fixedSubscriptionOrder.contains(context.account.peerId) {
|
||||
sortedItems.append(accountItem)
|
||||
} else {
|
||||
if startedWithUnseen {
|
||||
if accountItem.hasUnseen || accountItem.hasPending {
|
||||
sortedItems.append(accountItem)
|
||||
@ -570,6 +573,7 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
sortedItems.append(accountItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
for peerId in self.fixedSubscriptionOrder {
|
||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
||||
if preFilterOrder {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,15 +440,21 @@ 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 {
|
||||
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 {
|
||||
if notEmpty {
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
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)
|
||||
|
||||
@ -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] = []
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user