diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 12c1d3ccbb..1fa417f0d2 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2671,7 +2671,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } }))) - items.append(.action(ContextMenuActionItem(text: "Hide", icon: { theme in + items.append(.action(ContextMenuActionItem(text: "Move to Contacts", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MoveToContacts"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) @@ -2680,8 +2680,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return } self.context.engine.peers.updatePeerStoriesHidden(id: peer.id, isHidden: true) - - }))) } diff --git a/submodules/ContactListUI/BUILD b/submodules/ContactListUI/BUILD index ff7d9bb750..cdcf365c4a 100644 --- a/submodules/ContactListUI/BUILD +++ b/submodules/ContactListUI/BUILD @@ -42,6 +42,7 @@ swift_library( "//submodules/TelegramUI/Components/ChatListTitleView", "//submodules/TelegramUI/Components/ChatListHeaderComponent", "//submodules/ComponentFlow", + "//submodules/UndoUI", ], visibility = [ "//visibility:public", diff --git a/submodules/ContactListUI/Sources/ContactContextMenus.swift b/submodules/ContactListUI/Sources/ContactContextMenus.swift index 5eb4121f16..b088134556 100644 --- a/submodules/ContactListUI/Sources/ContactContextMenus.swift +++ b/submodules/ContactListUI/Sources/ContactContextMenus.swift @@ -9,6 +9,7 @@ import AlertUI import PresentationDataUtils import OverlayStatusController import LocalizedPeerData +import UndoUI func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, contactsController: ContactsController?, isStories: Bool) -> Signal<[ContextMenuItem], NoError> { let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings @@ -16,20 +17,83 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con return context.engine.data.get( TelegramEngine.EngineData.Item.Peer.Peer(id: peerId), TelegramEngine.EngineData.Item.Peer.AreVoiceCallsAvailable(id: peerId), - TelegramEngine.EngineData.Item.Peer.AreVideoCallsAvailable(id: peerId) + TelegramEngine.EngineData.Item.Peer.AreVideoCallsAvailable(id: peerId), + TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId) ) - |> map { [weak contactsController] peer, areVoiceCallsAvailable, areVideoCallsAvailable -> [ContextMenuItem] in + |> map { [weak contactsController] peer, areVoiceCallsAvailable, areVideoCallsAvailable, notificationSettings -> [ContextMenuItem] in var items: [ContextMenuItem] = [] if isStories { //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Unhide", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unarchive"), color: theme.contextMenu.primaryColor) + + items.append(.action(ContextMenuActionItem(text: "View Profile", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + c.dismiss(completion: { + let _ = (context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) + ) + |> deliverOnMainQueue).start(next: { peer in + guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) else { + return + } + (contactsController?.navigationController as? NavigationController)?.pushViewController(controller) + }) + }) + }))) + + let isMuted = notificationSettings.storiesMuted == true + items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Not Notify", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) + }, action: { _, f in + f(.default) + + let _ = context.engine.peers.togglePeerStoriesMuted(peerId: peerId).start() + + if let peer { + let iconColor = UIColor.white + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + if isMuted { + contactsController?.present(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will now get a notification whenever **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + } else { + contactsController?.present(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will no longer receive a notification when **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + } + } + }))) + + items.append(.action(ContextMenuActionItem(text: "Move to chats", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MoveToChats"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.default) context.engine.peers.updatePeerStoriesHidden(id: peerId, isHidden: false) }))) + + return items } items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_SendMessage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.contextMenu.primaryColor) }, action: { _, f in diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 47d3505934..3014b5126b 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -559,67 +559,6 @@ public class ContactsController: ViewController { self.push(storyContainerScreen) }) } - - /*componentView.storyContextPeerAction = { [weak self] sourceNode, gesture, peer in - guard let self else { - return - } - - var items: [ContextMenuItem] = [] - - //TODO:localize - if peer.id == self.context.account.peerId { - } else { - items.append(.action(ContextMenuActionItem(text: "View Profile", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] c, _ in - c.dismiss(completion: { - guard let self else { - return - } - - let _ = (self.context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: peer.id) - ) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let self else { - return - } - guard let peer = peer, let controller = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) else { - return - } - (self.navigationController as? NavigationController)?.pushViewController(controller) - }) - }) - }))) - /*items.append(.action(ContextMenuActionItem(text: "Mute", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor) - }, action: { _, f in - f(.default) - })))*/ - - if case let .user(user) = peer, let storiesHidden = user.storiesHidden, storiesHidden { - items.append(.action(ContextMenuActionItem(text: "Unarchive", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unarchive"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let self else { - return - } - self.context.engine.peers.updatePeerStoriesHidden(id: peer.id, isHidden: false) - }))) - } - } - - if items.isEmpty { - return - } - - let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: self, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture) - self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller) - } - }*/ } @objc private func sortPressed() { diff --git a/submodules/ContactListUI/Sources/ContactsControllerNode.swift b/submodules/ContactListUI/Sources/ContactsControllerNode.swift index c27de73dfe..0b46c1cb32 100644 --- a/submodules/ContactListUI/Sources/ContactsControllerNode.swift +++ b/submodules/ContactListUI/Sources/ContactsControllerNode.swift @@ -527,10 +527,18 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { guard let contactsController = self.controller else { return } - let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) - chatController.canReadHistory.set(false) - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: contactContextMenuItems(context: self.context, peerId: peer.id, contactsController: contactsController, isStories: isStories) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture) - contactsController.presentInGlobalOverlay(contextController) + + let items = contactContextMenuItems(context: self.context, peerId: peer.id, contactsController: contactsController, isStories: isStories) |> map { ContextController.Items(content: .list($0)) } + + if isStories, let node = node?.subnodes?.first(where: { $0 is ContextExtractedContentContainingNode }) as? ContextExtractedContentContainingNode { + let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ContactContextExtractedContentSource(sourceNode: node, shouldBeDismissed: .single(false))), items: items, recognizer: nil, gesture: gesture) + contactsController.presentInGlobalOverlay(controller) + } else { + let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) + chatController.canReadHistory.set(false) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: items, gesture: gesture) + contactsController.presentInGlobalOverlay(contextController) + } } func activateSearch(placeholderNode: SearchBarPlaceholderNode) { @@ -616,3 +624,26 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { } } } + +private final class ContactContextExtractedContentSource: ContextExtractedContentSource { + let keepInPlace: Bool = false + let ignoreContentTouches: Bool = true + let blurBackground: Bool = true + + let shouldBeDismissed: Signal + + private let sourceNode: ContextExtractedContentContainingNode + + init(sourceNode: ContextExtractedContentContainingNode, shouldBeDismissed: Signal? = nil) { + self.sourceNode = sourceNode + self.shouldBeDismissed = shouldBeDismissed ?? .single(false) + } + + func takeView() -> ContextControllerTakeViewInfo? { + return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds) + } + + func putBack() -> ContextControllerPutBackViewInfo? { + return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds) + } +}