From 2dd8e19143e7e8764c401a72a8c83b6cd22ac9ec Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 11 Feb 2024 02:09:24 +0400 Subject: [PATCH] Group stories --- .../Telegram-iOS/en.lproj/Localizable.strings | 8 ++ .../Sources/PeerInfoStoryGridScreen.swift | 95 +++++++++++-------- .../StoryItemSetContainerComponent.swift | 49 +++++++--- 3 files changed, 98 insertions(+), 54 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 745f6064bd..a623c46097 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -11291,3 +11291,11 @@ Sorry for the inconvenience."; "GroupBoost.BoostToUnrestrict" = "Boost the group %1$@ to remove messaging restrictions. Your boosts will help **%2$@** to unlock new features."; "Story.InputPlaceholderReplyInGroup" = "Comment Story..."; + +"Story.SendReactionAsGroupMessage" = "Send reaction as a message"; + +"StoryList.TooltipStoriesSavedToGroup_1" = "Story saved to groups's profile"; +"StoryList.TooltipStoriesSavedToGroup_any" = "%d stories saved to groups's profile."; +"Story.ToastRemovedFromGroupText" = "Story removed from the group page"; +"Story.ToastSavedToGroupTitle" = "Story saved to the group page"; +"Story.ToastSavedToGroupText" = "Posted stories can be viewed by others on the group page until an admin removes them."; diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift index 505d0b4b3b..8dba199363 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift @@ -348,50 +348,61 @@ final class PeerInfoStoryGridScreenComponent: Component { return } - switch component.scope { - case .saved: - let selectedCount = paneNode.selectedItems.count - let _ = component.context.engine.messages.updateStoriesArePinned(peerId: component.peerId, ids: paneNode.selectedItems, isPinned: false).start() - - paneNode.setIsSelectionModeActive(false) - (self.environment?.controller() as? PeerInfoStoryGridScreen)?.updateTitle() - - let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) - - let title: String = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(selectedCount)) - environment.controller()?.present(UndoOverlayController( - presentationData: presentationData, - content: .info(title: nil, text: title, timeout: nil, customUndoText: nil), - elevatedLayout: false, - animateInAsReplacement: false, - action: { _ in return false } - ), in: .current) - case .archive: - let _ = component.context.engine.messages.updateStoriesArePinned(peerId: component.peerId, ids: paneNode.selectedItems, isPinned: true).start() - - let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) - - let title: String - let text: String - - if component.peerId == component.context.account.peerId { - title = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(paneNode.selectedIds.count)) - text = presentationData.strings.StoryList_TooltipStoriesSavedToProfileText - } else { - title = presentationData.strings.StoryList_TooltipStoriesSavedToChannel(Int32(paneNode.selectedIds.count)) - text = presentationData.strings.Story_ToastSavedToChannelText + let _ = (component.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: component.peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let self, let peer else { + return + } + var isGroup = false + if case let .channel(channel) = peer, case .group = channel.info { + isGroup = true } - environment.controller()?.present(UndoOverlayController( - presentationData: presentationData, - content: .info(title: title, text: text, timeout: nil, customUndoText: nil), - elevatedLayout: false, - animateInAsReplacement: false, - action: { _ in return false } - ), in: .current) - - paneNode.clearSelection() - } + switch component.scope { + case .saved: + let selectedCount = paneNode.selectedItems.count + let _ = component.context.engine.messages.updateStoriesArePinned(peerId: component.peerId, ids: paneNode.selectedItems, isPinned: false).start() + + paneNode.setIsSelectionModeActive(false) + (self.environment?.controller() as? PeerInfoStoryGridScreen)?.updateTitle() + + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) + + let title: String = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(selectedCount)) + environment.controller()?.present(UndoOverlayController( + presentationData: presentationData, + content: .info(title: nil, text: title, timeout: nil, customUndoText: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + case .archive: + let _ = component.context.engine.messages.updateStoriesArePinned(peerId: component.peerId, ids: paneNode.selectedItems, isPinned: true).start() + + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) + + let title: String + let text: String + + if component.peerId == component.context.account.peerId { + title = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(paneNode.selectedIds.count)) + text = presentationData.strings.StoryList_TooltipStoriesSavedToProfileText + } else { + title = isGroup ? presentationData.strings.StoryList_TooltipStoriesSavedToGroup(Int32(paneNode.selectedIds.count)) : presentationData.strings.StoryList_TooltipStoriesSavedToChannel(Int32(paneNode.selectedIds.count)) + text = isGroup ? presentationData.strings.Story_ToastSavedToGroupText : presentationData.strings.Story_ToastSavedToChannelText + } + + environment.controller()?.present(UndoOverlayController( + presentationData: presentationData, + content: .info(title: title, text: text, timeout: nil, customUndoText: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + + paneNode.clearSelection() + } + }) } )), environment: {}, diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index 2b5467ff88..63b2c01cdd 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -1660,11 +1660,18 @@ public final class StoryItemSetContainerComponent: Component { var canShare = true var displayFooter = false if case let .channel(channel) = component.slice.peer { - displayFooter = true isChannel = true if channel.addressName == nil { canShare = false } + switch channel.info { + case .broadcast: + displayFooter = true + case .group: + if channel.flags.contains(.isCreator) || channel.hasPermission(.postStories) { + displayFooter = true + } + } } else if component.slice.peer.id == component.context.account.peerId { displayFooter = true } else if component.slice.item.storyItem.isPending { @@ -2752,6 +2759,24 @@ public final class StoryItemSetContainerComponent: Component { disabledPlaceholder = .text(component.strings.Story_FooterReplyUnavailable) } + var isChannel = false + var isGroup = false + var showMessageInputPanel = true + if case let .channel(channel) = component.slice.peer { + switch channel.info { + case .broadcast: + isChannel = true + showMessageInputPanel = false + case .group: + isGroup = true + if channel.flags.contains(.isCreator) || channel.hasPermission(.postStories) { + showMessageInputPanel = false + } + } + } else { + showMessageInputPanel = component.slice.peer.id != component.context.account.peerId + } + let inputPlaceholder: MessageInputPanelComponent.Placeholder if let stealthModeTimeout = component.stealthModeTimeout { let minutes = Int(stealthModeTimeout / 60) @@ -2787,7 +2812,7 @@ public final class StoryItemSetContainerComponent: Component { inputPlaceholder = .counter(items) } else { - inputPlaceholder = .plain(component.strings.Story_InputPlaceholderReplyPrivately) + inputPlaceholder = .plain(isGroup ? component.strings.Story_InputPlaceholderReplyInGroup : component.strings.Story_InputPlaceholderReplyPrivately) } let startTime22 = CFAbsoluteTimeGetCurrent() @@ -2811,13 +2836,8 @@ public final class StoryItemSetContainerComponent: Component { var inputPanelSize: CGSize? let startTime23 = CFAbsoluteTimeGetCurrent() - - var isChannel = false - if case .channel = component.slice.peer { - isChannel = true - } - - if component.slice.peer.id != component.context.account.peerId && !isChannel { + + if showMessageInputPanel { var haveLikeOptions = false if case .user = component.slice.peer { haveLikeOptions = true @@ -4381,7 +4401,7 @@ public final class StoryItemSetContainerComponent: Component { presentationData: component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme), items: reactionItems.map(ReactionContextItem.reaction), selectedItems: component.slice.item.storyItem.myReaction.flatMap { Set([$0]) } ?? Set(), - title: self.displayLikeReactions ? nil : component.strings.Story_SendReactionAsMessage, + title: self.displayLikeReactions ? nil : (isGroup ? component.strings.Story_SendReactionAsGroupMessage : component.strings.Story_SendReactionAsMessage), reactionsLocked: false, alwaysAllowPremiumReactions: false, allPresetReactionsAreAvailable: false, @@ -6394,11 +6414,16 @@ public final class StoryItemSetContainerComponent: Component { let _ = component.context.engine.messages.updateStoriesArePinned(peerId: component.slice.peer.id, ids: [component.slice.item.storyItem.id: component.slice.item.storyItem], isPinned: !component.slice.item.storyItem.isPinned).startStandalone() + var isGroup = false + if case let .channel(channel) = component.slice.peer, case .group = channel.info { + isGroup = true + } + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) if component.slice.item.storyItem.isPinned { self.scheduledStoryUnpinnedUndoOverlay = UndoOverlayController( presentationData: presentationData, - content: .info(title: nil, text: presentationData.strings.Story_ToastRemovedFromChannelText, timeout: nil, customUndoText: nil), + content: .info(title: nil, text: isGroup ? presentationData.strings.Story_ToastRemovedFromGroupText : presentationData.strings.Story_ToastRemovedFromChannelText, timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, blurred: true, @@ -6407,7 +6432,7 @@ public final class StoryItemSetContainerComponent: Component { } else { self.component?.presentController(UndoOverlayController( presentationData: presentationData, - content: .info(title: presentationData.strings.Story_ToastSavedToChannelTitle, text: presentationData.strings.Story_ToastSavedToChannelText, timeout: nil, customUndoText: nil), + content: .info(title: isGroup ? presentationData.strings.Story_ToastSavedToGroupTitle : presentationData.strings.Story_ToastSavedToChannelTitle, text: isGroup ? presentationData.strings.Story_ToastSavedToGroupText : presentationData.strings.Story_ToastSavedToChannelText, timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, blurred: true,