diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index de7e519581..81b2135018 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -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: %@"; diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift index f43155bce9..78cae803d2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift @@ -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 diff --git a/submodules/TelegramUI/Resources/Animations/generic_reaction_inline_pattern.json b/submodules/TelegramUI/Resources/Animations/generic_reaction_inline_pattern.json new file mode 100644 index 0000000000..2f4a0380b3 --- /dev/null +++ b/submodules/TelegramUI/Resources/Animations/generic_reaction_inline_pattern.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":91,"w":512,"h":512,"nm":"MAIN","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]},"a":{"a":0,"k":[-58,36,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[256,-256],[256,256],[-256,256],[-256,-256]],"c":true}},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":40},"w":{"a":0,"k":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[-58,36]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 1","bm":0,"hd":false}],"ip":0,"op":180,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL SCALE ALL","sr":1,"ks":{"o":{"a":0,"k":0},"p":{"a":0,"k":[256,256,0]},"s":{"a":0,"k":[99,99,100]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"placeholder_1","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":41,"s":[100]},{"t":48.884765625,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.504,"y":0.922},"o":{"x":0.195,"y":0.205},"t":3,"s":[-3.909,-18.385,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.46,"y":1},"o":{"x":0.279,"y":0.04},"t":13,"s":[-22.092,-88.1,0],"to":[0,0,0],"ti":[0,0,0]},{"t":59,"s":[-31.592,275.598,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[12,12,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[20,20,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":36,"s":[28,28,100]},{"t":47,"s":[4,4,100]}]}},"ao":0,"w":512,"h":512,"ip":3,"op":46,"st":-33,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"placeholder_2","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":43,"s":[100]},{"t":53,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.109,"y":0.548},"o":{"x":0.02,"y":0},"t":3,"s":[-23.388,-13.688,0],"to":[10.707,-41.715,0],"ti":[-38.374,0.791,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.474,"y":0.378},"t":13,"s":[45.744,-148.649,0],"to":[43.367,-0.894,0],"ti":[-12.625,-246.426,0]},{"t":61,"s":[172.813,307.068,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":3,"s":[-8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[-14,14,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":43,"s":[-21,21,100]},{"t":52,"s":[-4,4,100]}]}},"ao":0,"w":512,"h":512,"ip":3,"op":49,"st":-117,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"placeholder_3","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":47,"s":[100]},{"t":55.8671875,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.417,"y":0.808},"o":{"x":0.137,"y":0.309},"t":4,"s":[-25.479,-36.14,0],"to":[-14.958,-20.45,0],"ti":[37.448,-4.406,0]},{"i":{"x":0.434,"y":1},"o":{"x":0.385,"y":0.212},"t":17,"s":[-144.226,-140.579,0],"to":[-42.843,5.041,0],"ti":[0,0,0]},{"t":73.47265625,"s":[-222.086,269.091,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":4,"s":[15,15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.175,0.175,-3.333]},"t":42,"s":[24,24,100]},{"t":55,"s":[5,5,100]}]}},"ao":0,"w":512,"h":512,"ip":4,"op":53,"st":4,"bm":0},{"ddd":0,"ind":11,"ty":0,"nm":"placeholder_4","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":55,"s":[100]},{"t":65,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.266,"y":0.874},"o":{"x":0.02,"y":0},"t":7,"s":[0.959,-4.44,0],"to":[-18.201,-59.818,0],"ti":[35.75,1.133,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.556,"y":0.158},"t":19,"s":[-62.024,-177.109,0],"to":[-53.216,3.549,0],"ti":[0,0,0]},{"t":74,"s":[-112.134,339.231,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[-12,12,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":53,"s":[-24,24,100]},{"t":63,"s":[-4,4,100]}]}},"ao":0,"w":512,"h":512,"ip":8,"op":61,"st":5,"bm":0},{"ddd":0,"ind":12,"ty":0,"nm":"placeholder_5","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":60,"s":[100]},{"t":70.109375,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.069,"y":0.731},"o":{"x":0.02,"y":0},"t":5,"s":[25.869,-26.788,0],"to":[14.597,-73.616,0],"ti":[-41.626,1.096,0]},{"i":{"x":0.705,"y":1},"o":{"x":0.466,"y":0.207},"t":20,"s":[98.524,-213.609,0],"to":[50.945,-1.349,0],"ti":[-11.393,-177.824,0]},{"t":76,"s":[194.127,275.605,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":5,"s":[8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[15,15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":57.842,"s":[20,20,100]},{"t":69,"s":[7,7,100]}]}},"ao":0,"w":512,"h":512,"ip":5,"op":67,"st":1,"bm":0},{"ddd":0,"ind":13,"ty":0,"nm":"placeholder_6","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":66,"s":[100]},{"t":77,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.02,"y":0},"t":5,"s":[-13.449,-6.509,0],"to":[0,0,0],"ti":[-14.652,1.25,0]},{"i":{"x":0.767,"y":0.698},"o":{"x":0.43,"y":0},"t":21,"s":[-3.854,-220.909,0],"to":[15.073,-1.286,0],"ti":[0.606,-106.051,0]},{"t":79,"s":[24.793,345.5,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":7,"s":[-10,10,100]},{"i":{"x":[0.45,0.45,0.45],"y":[1,1,1]},"o":{"x":[0.27,0.27,0.27],"y":[0,0,0]},"t":62,"s":[-24,24,100]},{"t":75,"s":[-8,5,100]}]}},"ao":0,"w":512,"h":512,"ip":5,"op":72,"st":-86,"bm":0},{"ddd":0,"ind":14,"ty":0,"nm":"placeholder_7","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":50,"s":[100]},{"t":60,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.109,"y":0.78},"o":{"x":0.02,"y":0},"t":8,"s":[-4.388,-33.688,0],"to":[5.707,-35.715,0],"ti":[-29.498,-0.693,0]},{"i":{"x":0.708,"y":1},"o":{"x":0.474,"y":0.154},"t":19,"s":[31.744,-160.649,0],"to":[38.182,0.896,0],"ti":[-12.625,-187.426,0]},{"t":67,"s":[98.813,287.068,0]}]},"a":{"a":0,"k":[256,256,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[8,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":19,"s":[14,14,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":50,"s":[17,17,100]},{"t":60,"s":[5,5,100]}]}},"ao":0,"w":512,"h":512,"ip":8,"op":56,"st":-40,"bm":0}]} \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 9bac377525..f02d565b51 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -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 } } diff --git a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift index 6ce46af50a..3f1699fb42 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift @@ -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)