Support private channel stories in chat

This commit is contained in:
Ali 2023-09-17 20:29:28 +02:00
parent ae8e948b95
commit 1a08a9e2ba
5 changed files with 73 additions and 20 deletions

View File

@ -10046,3 +10046,6 @@ Sorry for the inconvenience.";
"Story.Context.RemoveFromChannel" = "Remove from Posts";
"Story.StealthModePlaceholder" = "Stealth Mode active — {m}:{s}";
"Chat.ReplyStoryPrivateChannel" = "Private story";
"Message.ForwardedUnavailableStoryShort" = "Private Story\nFrom: %@";

View File

@ -58,11 +58,17 @@ private final class InfoButtonNode: HighlightableButtonNode {
}
public class ChatMessageForwardInfoNode: ASDisplayNode {
public enum StoryType {
case regular
case expired
case unavailable
}
public struct StoryData: Equatable {
public var isExpired: Bool
public var storyType: StoryType
public init(isExpired: Bool) {
self.isExpired = isExpired
public init(storyType: StoryType) {
self.storyType = storyType
}
}
@ -159,10 +165,13 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
titleColor = incoming ? presentationData.theme.theme.chat.message.incoming.accentTextColor : presentationData.theme.theme.chat.message.outgoing.accentTextColor
if let storyData = storyData {
if storyData.isExpired {
completeSourceString = strings.Message_ForwardedExpiredStoryShort(peerString)
} else {
switch storyData.storyType {
case .regular:
completeSourceString = strings.Message_ForwardedStoryShort(peerString)
case .expired:
completeSourceString = strings.Message_ForwardedExpiredStoryShort(peerString)
case .unavailable:
completeSourceString = strings.Message_ForwardedUnavailableStoryShort(peerString)
}
} else {
completeSourceString = strings.Message_ForwardedMessageShort(peerString)
@ -251,8 +260,13 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
infoWidth += leftOffset
var cutout: TextNodeCutout?
if let storyData, storyData.isExpired {
cutout = TextNodeCutout(topLeft: CGSize(width: 16.0, height: 10.0))
if let storyData {
switch storyData.storyType {
case .regular, .unavailable:
break
case .expired:
cutout = TextNodeCutout(topLeft: CGSize(width: 16.0, height: 10.0))
}
}
let (textLayout, textApply) = textNodeLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - credibilityIconWidth - infoWidth, height: constrainedSize.height), alignment: .natural, cutout: cutout, insets: UIEdgeInsets()))
@ -273,7 +287,7 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
}
textNode.frame = CGRect(origin: CGPoint(x: leftOffset, y: 0.0), size: textLayout.size)
if let storyData, storyData.isExpired {
if let storyData, case .expired = storyData.storyType {
let expiredStoryIconView: UIImageView
if let current = node.expiredStoryIconView {
expiredStoryIconView = current

File diff suppressed because one or more lines are too long

View File

@ -137,14 +137,26 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
result.append((message, ChatMessageStoryMentionContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform, neighborSpacing: .default)))
}
} else {
if let storyItem = message.associatedStories[story.storyId], storyItem.data.isEmpty {
} else {
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media, neighborSpacing: .default)))
var hideStory = false
if let peer = message.peers[story.storyId.peerId] as? TelegramChannel, peer.username == nil, peer.usernames.isEmpty {
switch peer.participationStatus {
case .member:
break
case .kicked, .left:
hideStory = true
}
}
if let storyItem = message.associatedStories[story.storyId], let storedItem = storyItem.get(Stories.StoredItem.self), case let .item(item) = storedItem {
if !item.text.isEmpty {
isStoryWithText = true
if !hideStory {
if let storyItem = message.associatedStories[story.storyId], storyItem.data.isEmpty {
} else {
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media, neighborSpacing: .default)))
}
if let storyItem = message.associatedStories[story.storyId], let storedItem = storyItem.get(Stories.StoredItem.self), case let .item(item) = storedItem {
if !item.text.isEmpty {
isStoryWithText = true
}
}
}
}
@ -2049,15 +2061,23 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
forwardSource = firstMessage.peers[storyMedia.storyId.peerId]
var isExpired: Bool = false
var storyType: ChatMessageForwardInfoNode.StoryType = .regular
if let storyItem = firstMessage.associatedStories[storyMedia.storyId], storyItem.data.isEmpty {
isExpired = true
storyType = .expired
}
if let peer = firstMessage.peers[storyMedia.storyId.peerId] as? TelegramChannel, peer.username == nil, peer.usernames.isEmpty {
switch peer.participationStatus {
case .member:
break
case .kicked, .left:
storyType = .unavailable
}
}
let sizeAndApply = forwardInfoLayout(item.presentationData, item.presentationData.strings, .bubble(incoming: incoming), forwardSource, nil, nil, ChatMessageForwardInfoNode.StoryData(isExpired: isExpired), CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude))
let sizeAndApply = forwardInfoLayout(item.presentationData, item.presentationData.strings, .bubble(incoming: incoming), forwardSource, nil, nil, ChatMessageForwardInfoNode.StoryData(storyType: storyType), CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude))
forwardInfoSizeApply = (sizeAndApply.0, { width in sizeAndApply.1(width) })
if isExpired {
if storyType != .regular {
headerSize.height += 6.0
}
@ -2065,7 +2085,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
headerSize.width = max(headerSize.width, forwardInfoSizeApply.0.width + bubbleWidthInsets)
headerSize.height += forwardInfoSizeApply.0.height
if isExpired {
if storyType != .regular {
headerSize.height += 16.0
}
}

View File

@ -138,10 +138,25 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
titleString = arguments.strings.User_DeletedAccount
}
isText = false
var hideStory = false
if let peer = arguments.parentMessage.peers[story.peerId] as? TelegramChannel, peer.username == nil, peer.usernames.isEmpty {
switch peer.participationStatus {
case .member:
break
case .kicked, .left:
hideStory = true
}
}
if let storyItem = arguments.parentMessage.associatedStories[story], storyItem.data.isEmpty {
isExpiredStory = true
textString = NSAttributedString(string: arguments.strings.Chat_ReplyExpiredStory)
isMedia = false
} else if hideStory {
isExpiredStory = true
textString = NSAttributedString(string: arguments.strings.Chat_ReplyStoryPrivateChannel)
isMedia = false
} else {
isStory = true
textString = NSAttributedString(string: arguments.strings.Chat_ReplyStory)