From 2e83cef3f7b51e77f7d661fac803491364a105cf Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 30 Jun 2023 02:38:24 +0200 Subject: [PATCH] Stories --- .../ChatListUI/Sources/ChatContextMenus.swift | 33 +- .../Sources/ChatListController.swift | 7 +- .../Sources/Node/ChatListItem.swift | 11 +- .../Sources/ContactContextMenus.swift | 16 +- .../NotificationExceptionControllerNode.swift | 61 +++- .../NotificationsAndSoundsController.swift | 17 +- .../NotificationsPeerCategoryController.swift | 200 ++++++++--- .../TelegramPeerNotificationSettings.swift | 24 +- .../Settings/GlobalNotificationSettings.swift | 32 +- .../ManagedGlobalNotificationSettings.swift | 120 ++++++- ...nagedPendingPeerNotificationSettings.swift | 71 +++- .../SyncCore_GlobalNotificationSettings.swift | 12 +- ...ore_TelegramPeerNotificationSettings.swift | 110 ++++-- .../Data/TelegramEngineData.swift | 62 ++++ .../ChangePeerNotificationSettings.swift | 88 ++++- .../Peers/NotificationExceptionsList.swift | 6 +- .../Sources/TelegramEngine/Peers/Peer.swift | 31 +- .../Peers/TelegramEnginePeers.swift | 20 +- .../NotificationExceptionsScreen.swift | 4 +- .../NotificationPeerExceptionController.swift | 325 +++++++++++++++--- .../Sources/StoryChatContent.swift | 30 +- .../Sources/StoryItemContentComponent.swift | 4 +- .../StoryItemSetContainerComponent.swift | 10 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 37 +- 24 files changed, 1074 insertions(+), 257 deletions(-) diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 3f8ba39fa5..f4644d9a8c 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -723,17 +723,18 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue } - let updatePeerStoryNotifications: (PeerId, PeerNotificationDisplayPreviews) -> Signal = { peerId, storyNotifications in - var isMuted: Bool? - switch storyNotifications { - case .default: - isMuted = nil - case .show: - isMuted = false - case .hide: - isMuted = true - } - return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, isMuted: isMuted) |> deliverOnMainQueue + let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal = { + peerId, mute in + return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue + } + + let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal = { + peerId, hideSender in + return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue + } + + let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal = { peerId, sound in + return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue } let defaultSound: PeerMessageSound @@ -769,8 +770,14 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: |> deliverOnMainQueue).start(next: { _ in }) - }, updatePeerStoryNotifications: { peerId, storyNotifications in - let _ = (updatePeerStoryNotifications(peerId, storyNotifications) + }, updatePeerStoriesMuted: { peerId, mute in + let _ = (updatePeerStoriesMuted(peerId, mute) + |> deliverOnMainQueue).start() + }, updatePeerStoriesHideSender: { peerId, hideSender in + let _ = (updatePeerStoriesHideSender(peerId, hideSender) + |> deliverOnMainQueue).start() + }, updatePeerStorySound: { peerId, sound in + let _ = (updatePeerStorySound(peerId, sound) |> deliverOnMainQueue).start() }, removePeerFromExceptions: { }, modifiedPeer: { diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index cd77da62c5..8353bf128e 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2581,9 +2581,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } let _ = (self.context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id) + TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id), + TelegramEngine.EngineData.Item.NotificationSettings.Global() ) - |> deliverOnMainQueue).start(next: { [weak self] notificationSettings in + |> deliverOnMainQueue).start(next: { [weak self] notificationSettings, globalSettings in guard let self else { return } @@ -2639,7 +2640,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController }) }))) - let isMuted = notificationSettings.storiesMuted == true + let isMuted = resolvedAreStoriesMuted(globalSettings: globalSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings()) items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Don't Notify", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index e1d07a9672..9da6263f59 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -3843,6 +3843,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + guard let item = self.item else { + return nil + } + if let compoundTextButtonNode = self.compoundTextButtonNode, let compoundHighlightingNode = self.compoundHighlightingNode, compoundHighlightingNode.alpha != 0.0 { let localPoint = self.view.convert(point, to: compoundHighlightingNode.view) var matches = false @@ -3857,8 +3861,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } } - if let avatarStoryIndicatorView = self.avatarStoryIndicator?.view, let result = avatarStoryIndicatorView.hitTest(self.view.convert(point, to: avatarStoryIndicatorView), with: event) { - return result + if let _ = item.interaction.inlineNavigationLocation { + } else { + if let avatarStoryIndicatorView = self.avatarStoryIndicator?.view, let result = avatarStoryIndicatorView.hitTest(self.view.convert(point, to: avatarStoryIndicatorView), with: event) { + return result + } } return super.hitTest(point, with: event) diff --git a/submodules/ContactListUI/Sources/ContactContextMenus.swift b/submodules/ContactListUI/Sources/ContactContextMenus.swift index 2c499de1e9..f5e7cbcd22 100644 --- a/submodules/ContactListUI/Sources/ContactContextMenus.swift +++ b/submodules/ContactListUI/Sources/ContactContextMenus.swift @@ -19,9 +19,14 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con 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.NotificationSettings(id: peerId) + TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId), + TelegramEngine.EngineData.Item.NotificationSettings.Global() ) - |> map { [weak contactsController] peer, areVoiceCallsAvailable, areVideoCallsAvailable, notificationSettings -> [ContextMenuItem] in + |> map { [weak contactsController] peer, areVoiceCallsAvailable, areVideoCallsAvailable, notificationSettings, globalSettings -> [ContextMenuItem] in + guard let peer else { + return [] + } + var items: [ContextMenuItem] = [] if isStories { @@ -42,7 +47,8 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con }) }))) - let isMuted = notificationSettings.storiesMuted == true + let isMuted = resolvedAreStoriesMuted(globalSettings: globalSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings()) + items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Don't 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 @@ -50,7 +56,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con let _ = context.engine.peers.togglePeerStoriesMuted(peerId: peerId).start() - if let peer { + do { let iconColor = UIColor.white let presentationData = context.sharedContext.currentPresentationData.with { $0 } if isMuted { @@ -96,7 +102,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con return } - if let peer { + do { let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY + 1.0), size: CGSize()) let tooltipController = TooltipScreen( context: context, diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift index 7b2bdaa0da..12126be1ea 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift @@ -62,8 +62,16 @@ private final class NotificationExceptionState : Equatable { return NotificationExceptionState(mode: mode.withUpdatedPeerDisplayPreviews(peer, displayPreviews), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) } - func withUpdatedPeerStoryNotifications(_ peer: EnginePeer, _ storyNotifications: PeerNotificationDisplayPreviews) -> NotificationExceptionState { - return NotificationExceptionState(mode: mode.withUpdatedPeerStoryNotifications(peer, storyNotifications), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) + func withUpdatedPeerStoriesMuted(_ peer: EnginePeer, _ mute: PeerStoryNotificationSettings.Mute) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStoriesMuted(peer, mute), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) + } + + func withUpdatedPeerStoriesHideSender(_ peer: EnginePeer, _ hideSender: PeerStoryNotificationSettings.HideSender) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStoriesHideSender(peer, hideSender), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) + } + + func withUpdatedPeerStorySound(_ peer: EnginePeer, _ sound: PeerMessageSound) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStorySound(peer, sound), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) } static func == (lhs: NotificationExceptionState, rhs: NotificationExceptionState) -> Bool { @@ -584,17 +592,18 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode { return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue } - let updatePeerStoryNotifications: (PeerId, PeerNotificationDisplayPreviews) -> Signal = { peerId, storyNotifications in - var isMuted: Bool? - switch storyNotifications { - case .default: - isMuted = nil - case .show: - isMuted = false - case .hide: - isMuted = true - } - return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, isMuted: isMuted) |> deliverOnMainQueue + let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal = { + peerId, mute in + return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue + } + + let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal = { + peerId, hideSender in + return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue + } + + let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal = { peerId, sound in + return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue } self.backgroundColor = presentationData.theme.list.blocksBackgroundColor @@ -670,12 +679,32 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode { } updateNotificationsView({}) }) - }, updatePeerStoryNotifications: { peerId, displayPreviews in + }, updatePeerStoriesMuted: { peerId, mute in updateNotificationsDisposable.set(nil) - _ = combineLatest(updatePeerStoryNotifications(peerId, displayPreviews), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + let _ = combineLatest(updatePeerStoriesMuted(peerId, mute), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in if let peer = peer { updateState { value in - return value.withUpdatedPeerStoryNotifications(peer, displayPreviews) + return value.withUpdatedPeerStoriesMuted(peer, mute) + } + } + updateNotificationsView({}) + }) + }, updatePeerStoriesHideSender: { peerId, hideSender in + updateNotificationsDisposable.set(nil) + let _ = combineLatest(updatePeerStoriesHideSender(peerId, hideSender), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + if let peer = peer { + updateState { value in + return value.withUpdatedPeerStoriesHideSender(peer, hideSender) + } + } + updateNotificationsView({}) + }) + }, updatePeerStorySound: { peerId, sound in + updateNotificationsDisposable.set(nil) + let _ = combineLatest(updatePeerStorySound(peerId, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + if let peer = peer { + updateState { value in + return value.withUpdatedPeerStorySound(peer, sound) } } updateNotificationsView({}) diff --git a/submodules/SettingsUI/Sources/Notifications/NotificationsAndSoundsController.swift b/submodules/SettingsUI/Sources/Notifications/NotificationsAndSoundsController.swift index 68d17571c8..1d9c6d06d3 100644 --- a/submodules/SettingsUI/Sources/Notifications/NotificationsAndSoundsController.swift +++ b/submodules/SettingsUI/Sources/Notifications/NotificationsAndSoundsController.swift @@ -551,8 +551,19 @@ private func notificationsAndSoundsEntries(authorizationStatus: AccessType, warn entries.append(.privateChats(presentationData.theme, presentationData.strings.Notifications_PrivateChats, !exceptions.users.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.users.peerIds.count)) : "", globalSettings.privateChats.enabled ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off)) entries.append(.groupChats(presentationData.theme, presentationData.strings.Notifications_GroupChats, !exceptions.groups.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.groups.peerIds.count)) : "", globalSettings.groupChats.enabled ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off)) entries.append(.channels(presentationData.theme, presentationData.strings.Notifications_Channels, !exceptions.channels.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.channels.peerIds.count)) : "", globalSettings.channels.enabled ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off)) + //TODO:localize - entries.append(.stories(presentationData.theme, "Stories", !exceptions.stories.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.stories.peerIds.count)) : "", globalSettings.privateChats.storiesMuted != true ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off)) + let storiesValue: String + switch globalSettings.privateChats.storySettings.mute { + case .default: + storiesValue = "Top 5" + case .muted: + storiesValue = presentationData.strings.Notifications_Off + case .unmuted: + storiesValue = presentationData.strings.Notifications_On + } + + entries.append(.stories(presentationData.theme, "Stories", !exceptions.stories.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.stories.peerIds.count)) : "", storiesValue)) entries.append(.inAppHeader(presentationData.theme, presentationData.strings.Notifications_InAppNotifications.uppercased())) entries.append(.inAppSounds(presentationData.theme, presentationData.strings.Notifications_InAppNotificationsSounds, inAppSettings.playSounds)) @@ -730,6 +741,8 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions let exceptionsSignal = Signal.single(exceptionsList) |> then(context.engine.peers.notificationExceptionsList() |> map(Optional.init)) + let defaultStorySettings = PeerStoryNotificationSettings.default + notificationExceptions.set(exceptionsSignal |> map { list -> (NotificationExceptionMode, NotificationExceptionMode, NotificationExceptionMode, NotificationExceptionMode) in var users:[PeerId : NotificationExceptionWrapper] = [:] var groups: [PeerId : NotificationExceptionWrapper] = [:] @@ -738,7 +751,7 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions if let list = list { for (key, value) in list.settings { if let peer = list.peers[key], !peer.debugDisplayTitle.isEmpty, peer.id != context.account.peerId { - if value.storiesMuted != nil { + if value.storySettings != defaultStorySettings { stories[key] = NotificationExceptionWrapper(settings: value, peer: EnginePeer(peer)) } diff --git a/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift b/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift index 740b463a24..9930d3b485 100644 --- a/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift +++ b/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift @@ -37,6 +37,7 @@ private final class NotificationsPeerCategoryControllerArguments { let soundSelectionDisposable: MetaDisposable let updateEnabled: (Bool) -> Void + let updateEnabledImportant: (Bool) -> Void let updatePreviews: (Bool) -> Void let openSound: (PeerMessageSound) -> Void @@ -49,11 +50,12 @@ private final class NotificationsPeerCategoryControllerArguments { let updatedExceptionMode: (NotificationExceptionMode) -> Void - init(context: AccountContext, soundSelectionDisposable: MetaDisposable, updateEnabled: @escaping (Bool) -> Void, updatePreviews: @escaping (Bool) -> Void, openSound: @escaping (PeerMessageSound) -> Void, addException: @escaping () -> Void, openException: @escaping (EnginePeer) -> Void, removeAllExceptions: @escaping () -> Void, updateRevealedPeerId: @escaping (EnginePeer.Id?) -> Void, removePeer: @escaping (EnginePeer) -> Void, updatedExceptionMode: @escaping (NotificationExceptionMode) -> Void) { + init(context: AccountContext, soundSelectionDisposable: MetaDisposable, updateEnabled: @escaping (Bool) -> Void, updateEnabledImportant: @escaping (Bool) -> Void, updatePreviews: @escaping (Bool) -> Void, openSound: @escaping (PeerMessageSound) -> Void, addException: @escaping () -> Void, openException: @escaping (EnginePeer) -> Void, removeAllExceptions: @escaping () -> Void, updateRevealedPeerId: @escaping (EnginePeer.Id?) -> Void, removePeer: @escaping (EnginePeer) -> Void, updatedExceptionMode: @escaping (NotificationExceptionMode) -> Void) { self.context = context self.soundSelectionDisposable = soundSelectionDisposable self.updateEnabled = updateEnabled + self.updateEnabledImportant = updateEnabledImportant self.updatePreviews = updatePreviews self.openSound = openSound @@ -90,6 +92,8 @@ public enum NotificationsPeerCategoryEntryTag: ItemListItemTag { private enum NotificationsPeerCategoryEntry: ItemListNodeEntry { case enable(PresentationTheme, String, Bool) + case enableImportant(PresentationTheme, String, Bool) + case importantInfo(PresentationTheme, String) case optionsHeader(PresentationTheme, String) case previews(PresentationTheme, String, Bool) case sound(PresentationTheme, String, String, PeerMessageSound) @@ -101,7 +105,7 @@ private enum NotificationsPeerCategoryEntry: ItemListNodeEntry { var section: ItemListSectionId { switch self { - case .enable: + case .enable, .enableImportant, .importantInfo: return NotificationsPeerCategorySection.enable.rawValue case .optionsHeader, .previews, .sound: return NotificationsPeerCategorySection.options.rawValue @@ -114,18 +118,22 @@ private enum NotificationsPeerCategoryEntry: ItemListNodeEntry { switch self { case .enable: return 0 - case .optionsHeader: + case .enableImportant: return 1 - case .previews: + case .importantInfo: return 2 - case .sound: + case .optionsHeader: return 3 - case .exceptionsHeader: + case .previews: return 4 - case .addException: + case .sound: return 5 + case .exceptionsHeader: + return 6 + case .addException: + return 7 case let .exception(index, _, _, _, _, _, _, _, _, _): - return 6 + index + return 8 + index case .removeAllExceptions: return 100000 } @@ -152,6 +160,18 @@ private enum NotificationsPeerCategoryEntry: ItemListNodeEntry { } else { return false } + case let .enableImportant(lhsTheme, lhsText, lhsValue): + if case let .enableImportant(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { + return true + } else { + return false + } + case let .importantInfo(lhsTheme, lhsText): + if case let .importantInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } case let .optionsHeader(lhsTheme, lhsText): if case let .optionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { return true @@ -209,6 +229,12 @@ private enum NotificationsPeerCategoryEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { updatedValue in arguments.updateEnabled(updatedValue) }, tag: self.tag) + case let .enableImportant(_, text, value): + return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { updatedValue in + arguments.updateEnabledImportant(updatedValue) + }, tag: self.tag) + case let .importantInfo(_, text): + return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) case let .optionsHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .previews(_, text, value): @@ -266,7 +292,34 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor } if case .stories = category { - entries.append(.enable(presentationData.theme, "Show All Notifications", notificationSettings.storiesMuted == nil || notificationSettings.storiesMuted == false)) + var allEnabled = false + var importantEnabled = false + + switch notificationSettings.storySettings.mute { + case .muted: + allEnabled = false + importantEnabled = false + case .unmuted: + allEnabled = true + importantEnabled = true + case .default: + allEnabled = false + importantEnabled = true + } + + //TODO:localize + entries.append(.enable(presentationData.theme, "Show All Notifications", allEnabled)) + if !allEnabled { + entries.append(.enableImportant(presentationData.theme, "Show Important Notifications", importantEnabled)) + entries.append(.importantInfo(presentationData.theme, "Always on for top 5 contacts.")) + } + + if notificationSettings.enabled || !notificationExceptions.isEmpty { + entries.append(.optionsHeader(presentationData.theme, presentationData.strings.Notifications_Options.uppercased())) + + entries.append(.previews(presentationData.theme, "Display Author Name", notificationSettings.storySettings.hideSender != .hide)) + entries.append(.sound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: filteredGlobalSound(notificationSettings.storySettings.sound)), filteredGlobalSound(notificationSettings.storySettings.sound))) + } } else { entries.append(.enable(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsAlert, notificationSettings.enabled)) @@ -280,7 +333,6 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsExceptions.uppercased())) entries.append(.addException(presentationData.theme, presentationData.strings.Notification_Exceptions_AddException)) - let sortedExceptions = notificationExceptions.settings.sorted(by: { lhs, rhs in let lhsName = lhs.value.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) let rhsName = rhs.value.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) @@ -312,11 +364,39 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor var title: String if case .stories = category { - if value.settings.storiesMuted == true { + var muted = false + if value.settings.storySettings.mute == .muted { + muted = true title = presentationData.strings.Notification_Exceptions_AlwaysOff } else { title = presentationData.strings.Notification_Exceptions_AlwaysOn } + + if !muted { + switch value.settings.storySettings.sound { + case .default: + break + default: + if !title.isEmpty { + title.append(", ") + } + title.append(presentationData.strings.Notification_Exceptions_SoundCustom) + } + switch value.settings.storySettings.hideSender { + case .default: + break + default: + if !title.isEmpty { + title += ", " + } + //TODO:localize + if case .show = value.settings.displayPreviews { + title += "Show Names" + } else { + title += "Hide Names" + } + } + } } else { var muted = false switch value.settings.muteState { @@ -427,8 +507,16 @@ private final class NotificationExceptionState : Equatable { return NotificationExceptionState(mode: mode.withUpdatedPeerDisplayPreviews(peer, displayPreviews), revealedPeerId: self.revealedPeerId, editing: self.editing) } - func withUpdatedPeerStoryNotifications(_ peer: EnginePeer, _ storyNotifications: PeerNotificationDisplayPreviews) -> NotificationExceptionState { - return NotificationExceptionState(mode: mode.withUpdatedPeerStoryNotifications(peer, storyNotifications), revealedPeerId: self.revealedPeerId, editing: self.editing) + func withUpdatedPeerStoriesMuted(_ peer: EnginePeer, _ mute: PeerStoryNotificationSettings.Mute) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStoriesMuted(peer, mute), revealedPeerId: self.revealedPeerId, editing: self.editing) + } + + func withUpdatedPeerStoriesHideSender(_ peer: EnginePeer, _ hideSender: PeerStoryNotificationSettings.HideSender) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStoriesHideSender(peer, hideSender), revealedPeerId: self.revealedPeerId, editing: self.editing) + } + + func withUpdatedPeerStorySound(_ peer: EnginePeer, _ sound: PeerMessageSound) -> NotificationExceptionState { + return NotificationExceptionState(mode: mode.withUpdatedPeerStorySound(peer, sound), revealedPeerId: self.revealedPeerId, editing: self.editing) } static func == (lhs: NotificationExceptionState, rhs: NotificationExceptionState) -> Bool { @@ -470,17 +558,18 @@ public func notificationsPeerCategoryController(context: AccountContext, categor return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: nil, displayPreviews: displayPreviews) |> deliverOnMainQueue } - let updatePeerStoryNotifications: (EnginePeer.Id, PeerNotificationDisplayPreviews) -> Signal = { peerId, storyNotifications in - var isMuted: Bool? - switch storyNotifications { - case .default: - isMuted = nil - case .show: - isMuted = false - case .hide: - isMuted = true - } - return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, isMuted: isMuted) |> deliverOnMainQueue + let updatePeerStoriesMuted: (EnginePeer.Id, PeerStoryNotificationSettings.Mute) -> Signal = { + peerId, mute in + return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue + } + + let updatePeerStoriesHideSender: (EnginePeer.Id, PeerStoryNotificationSettings.HideSender) -> Signal = { + peerId, hideSender in + return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue + } + + let updatePeerStorySound: (EnginePeer.Id, PeerMessageSound) -> Signal = { peerId, sound in + return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue } var peerIds: Set = Set(mode.peerIds) @@ -587,12 +676,32 @@ public func notificationsPeerCategoryController(context: AccountContext, categor } updateNotificationsView({}) }) - }, updatePeerStoryNotifications: { peerId, storyNotifications in + }, updatePeerStoriesMuted: { peerId, mute in updateNotificationsDisposable.set(nil) - _ = combineLatest(updatePeerStoryNotifications(peerId, storyNotifications), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + let _ = combineLatest(updatePeerStoriesMuted(peerId, mute), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in if let peer = peer { updateState { value in - return value.withUpdatedPeerStoryNotifications(peer, storyNotifications) + return value.withUpdatedPeerStoriesMuted(peer, mute) + } + } + updateNotificationsView({}) + }) + }, updatePeerStoriesHideSender: { peerId, hideSender in + updateNotificationsDisposable.set(nil) + let _ = combineLatest(updatePeerStoriesHideSender(peerId, hideSender), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + if let peer = peer { + updateState { value in + return value.withUpdatedPeerStoriesHideSender(peer, hideSender) + } + } + updateNotificationsView({}) + }) + }, updatePeerStorySound: { peerId, sound in + updateNotificationsDisposable.set(nil) + let _ = combineLatest(updatePeerStorySound(peerId, sound), context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).start(next: { _, peer in + if let peer = peer { + updateState { value in + return value.withUpdatedPeerStorySound(peer, sound) } } updateNotificationsView({}) @@ -608,7 +717,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor return } updateState { value in - return value.withUpdatedPeerStoryNotifications(peer, .default) + return value.withUpdatedPeerStorySound(peer, .default).withUpdatedPeerStoriesMuted(peer, .default).withUpdatedPeerStoriesHideSender(peer, .default) } updateNotificationsView({}) }) @@ -637,14 +746,25 @@ public func notificationsPeerCategoryController(context: AccountContext, categor let _ = updateGlobalNotificationSettingsInteractively(postbox: context.account.postbox, { settings in var settings = settings switch category { - case .privateChat: - settings.privateChats.enabled = value - case .group: - settings.groupChats.enabled = value - case .channel: - settings.channels.enabled = value - case .stories: - settings.privateChats.storiesMuted = !value + case .privateChat: + settings.privateChats.enabled = value + case .group: + settings.groupChats.enabled = value + case .channel: + settings.channels.enabled = value + case .stories: + settings.privateChats.storySettings.mute = value ? .unmuted : .default + } + return settings + }).start() + }, updateEnabledImportant: { value in + let _ = updateGlobalNotificationSettingsInteractively(postbox: context.account.postbox, { settings in + var settings = settings + switch category { + case .stories: + settings.privateChats.storySettings.mute = value ? .default : .muted + default: + break } return settings }).start() @@ -659,7 +779,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor case .channel: settings.channels.displayPreviews = value case .stories: - break + settings.privateChats.storySettings.hideSender = value ? .show : .hide } return settings }).start() @@ -675,7 +795,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor case .channel: settings.channels.sound = value case .stories: - break + settings.privateChats.storySettings.sound = value } return settings }).start() @@ -722,7 +842,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor updateState { state in var state = state for value in values { - state = state.withUpdatedPeerStoryNotifications(value.peer, .default) + state = state.withUpdatedPeerStorySound(value.peer, .default).withUpdatedPeerStoriesMuted(value.peer, .default).withUpdatedPeerStoriesHideSender(value.peer, .default) } return state } @@ -765,7 +885,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor |> deliverOnMainQueue).start(completed: { updateNotificationsDisposable.set(nil) updateState { value in - return value.withUpdatedPeerStoryNotifications(peer, .default) + return value.withUpdatedPeerStorySound(peer, .default).withUpdatedPeerStoriesMuted(peer, .default).withUpdatedPeerStoriesHideSender(peer, .default) } let _ = (context.engine.peers.removeCustomStoryNotificationSettings(peerIds: [peer.id]) |> deliverOnMainQueue).start(completed: { diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift index e8d76aa730..32bec8e14e 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift @@ -6,12 +6,15 @@ import TelegramApi extension TelegramPeerNotificationSettings { convenience init(apiSettings: Api.PeerNotifySettings) { switch apiSettings { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, _, _, _, _): + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, storiesHideSender, storiesIosSound, _, storiesDesktopSound): let sound: Api.NotificationSound? + let storiesSound: Api.NotificationSound? #if os(iOS) sound = iosSound + storiesSound = storiesIosSound #elseif os(macOS) sound = desktopSound + storiesSound = storiesDesktopSound #endif let muteState: PeerMuteState @@ -35,12 +38,25 @@ extension TelegramPeerNotificationSettings { displayPreviews = .default } - var storiesMutedValue: Bool? + let storiesMutedValue: PeerStoryNotificationSettings.Mute if let storiesMuted = storiesMuted { - storiesMutedValue = storiesMuted == .boolTrue + storiesMutedValue = storiesMuted == .boolTrue ? .muted : .unmuted + } else { + storiesMutedValue = .default } - self.init(muteState: muteState, messageSound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault), displayPreviews: displayPreviews, storiesMuted: storiesMutedValue) + var storiesHideSenderValue: PeerStoryNotificationSettings.HideSender + if let storiesHideSender = storiesHideSender { + storiesHideSenderValue = storiesHideSender == .boolTrue ? .hide : .show + } else { + storiesHideSenderValue = .default + } + + self.init(muteState: muteState, messageSound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault), displayPreviews: displayPreviews, storySettings: PeerStoryNotificationSettings( + mute: storiesMutedValue, + hideSender: storiesHideSenderValue, + sound: PeerMessageSound(apiSound: storiesSound ?? .notificationSoundDefault) + )) } } } diff --git a/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift index 48b0d6ba98..5503641a7b 100644 --- a/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift @@ -6,24 +6,48 @@ import TelegramApi extension MessageNotificationSettings { init(apiSettings: Api.PeerNotifySettings) { switch apiSettings { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, _, _, _, _): + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, storiesHideSender, storiesIosSound, _, storiesDesktopSound): let sound: Api.NotificationSound? + let storiesSound: Api.NotificationSound? #if os(iOS) sound = iosSound + storiesSound = storiesIosSound #elseif os(macOS) sound = desktopSound + storiesSound = storiesDesktopSound #endif + let displayPreviews: Bool if let showPreviews = showPreviews, case .boolFalse = showPreviews { displayPreviews = false } else { displayPreviews = true } - var storiesMutedValue: Bool? + + let storiesMutedValue: PeerStoryNotificationSettings.Mute if let storiesMuted = storiesMuted { - storiesMutedValue = storiesMuted == .boolTrue + storiesMutedValue = storiesMuted == .boolTrue ? .muted : .unmuted + } else { + storiesMutedValue = .default } - self = MessageNotificationSettings(enabled: muteUntil == 0, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault), storiesMuted: storiesMutedValue) + + var storiesHideSenderValue: PeerStoryNotificationSettings.HideSender + if let storiesHideSender = storiesHideSender { + storiesHideSenderValue = storiesHideSender == .boolTrue ? .hide : .show + } else { + storiesHideSenderValue = .default + } + + self = MessageNotificationSettings( + enabled: muteUntil == 0, + displayPreviews: displayPreviews, + sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault), + storySettings: PeerStoryNotificationSettings( + mute: storiesMutedValue, + hideSender: storiesHideSenderValue, + sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault) + ) + ) } } } diff --git a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift index aa893f7cce..e1463d6e50 100644 --- a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift @@ -116,12 +116,15 @@ private func fetchedNotificationSettings(network: Network) -> Signal map { chats, users, channels, contactsJoinedMuted in let chatsSettings: MessageNotificationSettings switch chats { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, _, _, _, _): + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, storiesHideSender, storiesIosSound, _, storiesDesktopSound): let sound: Api.NotificationSound? + let storiesSound: Api.NotificationSound? #if os(iOS) sound = iosSound + storiesSound = storiesIosSound #elseif os(macOS) sound = desktopSound + storiesSound = storiesDesktopSound #endif let enabled: Bool @@ -137,22 +140,43 @@ private func fetchedNotificationSettings(network: Network) -> Signal Signal Signal Signal { diff --git a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift index 1aa931a29a..0bbbb360be 100644 --- a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift @@ -130,13 +130,39 @@ func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: Pe if sound != nil { flags |= (1 << 3) } - var storiesMuted: Api.Bool? - if let storiesMutedValue = settings.storiesMuted { + + let storiesMuted: Api.Bool? + switch settings.storySettings.mute { + case .default: + storiesMuted = nil + case .muted: + storiesMuted = .boolTrue + case .unmuted: + storiesMuted = .boolFalse + } + if storiesMuted != nil { flags |= (1 << 6) - storiesMuted = storiesMutedValue ? .boolTrue : .boolFalse } - let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound, storiesMuted: storiesMuted, storiesHideSender: nil, storiesSound: nil) + let storiesHideSender: Api.Bool? + switch settings.storySettings.hideSender { + case .default: + storiesHideSender = nil + case .hide: + storiesHideSender = .boolTrue + case .show: + storiesHideSender = .boolFalse + } + if storiesHideSender != nil { + flags |= (1 << 7) + } + + let storiesSound: Api.NotificationSound? = settings.storySettings.sound.apiSound + if storiesSound != nil { + flags |= (1 << 8) + } + + let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound, storiesMuted: storiesMuted, storiesHideSender: storiesHideSender, storiesSound: storiesSound) return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyForumTopic(peer: inputPeer, topMsgId: Int32(clamping: threadId)), settings: inputSettings)) |> `catch` { _ -> Signal in return .single(.boolFalse) @@ -179,12 +205,39 @@ func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: Pe if sound != nil { flags |= (1 << 3) } - var storiesMuted: Api.Bool? - if let storiesMutedValue = settings.storiesMuted { - flags |= (1 << 6) - storiesMuted = storiesMutedValue ? .boolTrue : .boolFalse + + let storiesMuted: Api.Bool? + switch settings.storySettings.mute { + case .default: + storiesMuted = nil + case .muted: + storiesMuted = .boolTrue + case .unmuted: + storiesMuted = .boolFalse } - let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound, storiesMuted: storiesMuted, storiesHideSender: nil, storiesSound: nil) + if storiesMuted != nil { + flags |= (1 << 6) + } + + let storiesHideSender: Api.Bool? + switch settings.storySettings.hideSender { + case .default: + storiesHideSender = nil + case .hide: + storiesHideSender = .boolTrue + case .show: + storiesHideSender = .boolFalse + } + if storiesHideSender != nil { + flags |= (1 << 7) + } + + let storiesSound: Api.NotificationSound? = settings.storySettings.sound.apiSound + if storiesSound != nil { + flags |= (1 << 8) + } + + let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound, storiesMuted: storiesMuted, storiesHideSender: storiesHideSender, storiesSound: storiesSound) return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyPeer(peer: inputPeer), settings: inputSettings)) |> `catch` { _ -> Signal in return .single(.boolFalse) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift index a3d03cd13f..3600a305fa 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift @@ -4,17 +4,17 @@ public struct MessageNotificationSettings: Codable, Equatable { public var enabled: Bool public var displayPreviews: Bool public var sound: PeerMessageSound - public var storiesMuted: Bool? + public var storySettings: PeerStoryNotificationSettings public static var defaultSettings: MessageNotificationSettings { - return MessageNotificationSettings(enabled: true, displayPreviews: true, sound: defaultCloudPeerNotificationSound, storiesMuted: nil) + return MessageNotificationSettings(enabled: true, displayPreviews: true, sound: defaultCloudPeerNotificationSound, storySettings: PeerStoryNotificationSettings.default) } - public init(enabled: Bool, displayPreviews: Bool, sound: PeerMessageSound, storiesMuted: Bool?) { + public init(enabled: Bool, displayPreviews: Bool, sound: PeerMessageSound, storySettings: PeerStoryNotificationSettings) { self.enabled = enabled self.displayPreviews = displayPreviews self.sound = sound - self.storiesMuted = storiesMuted + self.storySettings = storySettings } public init(from decoder: Decoder) throws { @@ -25,7 +25,7 @@ public struct MessageNotificationSettings: Codable, Equatable { self.sound = try PeerMessageSound.decodeInline(container) - self.storiesMuted = try? container.decodeIfPresent(Bool.self, forKey: "st") + self.storySettings = try container.decodeIfPresent(PeerStoryNotificationSettings.self, forKey: "stor") ?? PeerStoryNotificationSettings(mute: .unmuted, hideSender: .show, sound: defaultCloudPeerNotificationSound) } public func encode(to encoder: Encoder) throws { @@ -34,7 +34,7 @@ public struct MessageNotificationSettings: Codable, Equatable { try container.encode((self.enabled ? 1 : 0) as Int32, forKey: "e") try container.encode((self.displayPreviews ? 1 : 0) as Int32, forKey: "p") try self.sound.encodeInline(&container) - try container.encodeIfPresent(self.storiesMuted, forKey: "st") + try container.encode(self.storySettings, forKey: "stor") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift index 9e5a068655..15324f1e1c 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift @@ -388,24 +388,90 @@ public enum PeerNotificationDisplayPreviews: Equatable, Codable { } } +public struct PeerStoryNotificationSettings: Codable, Equatable { + public enum CodingError: Error { + case generic + } + + public static var `default`: PeerStoryNotificationSettings { + return PeerStoryNotificationSettings(mute: .default, hideSender: .default, sound: .default) + } + + private enum CodingKeys: String, CodingKey { + case mute = "m" + case hideSender = "hs" + case sound = "s" + } + + public enum Mute: Int32, Codable { + case `default` = 0 + case unmuted = 1 + case muted = 2 + } + + public enum HideSender: Int32, Codable { + case `default` = 0 + case hide = 1 + case show = 2 + } + + public var mute: Mute + public var hideSender: HideSender + public var sound: PeerMessageSound + + public init( + mute: Mute, + hideSender: HideSender, + sound: PeerMessageSound + ) { + self.mute = mute + self.hideSender = hideSender + self.sound = sound + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + if let mute = Mute(rawValue: try container.decode(Int32.self, forKey: .mute)) { + self.mute = mute + } else { + throw CodingError.generic + } + if let hideSender = HideSender(rawValue: try container.decode(Int32.self, forKey: .hideSender)) { + self.hideSender = hideSender + } else { + throw CodingError.generic + } + self.sound = try container.decode(PeerMessageSound.self, forKey: .sound) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.mute.rawValue, forKey: .mute) + try container.encode(self.hideSender.rawValue, forKey: .hideSender) + try container.encode(self.sound, forKey: .sound) + } +} + public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Codable, Equatable { public let muteState: PeerMuteState public let messageSound: PeerMessageSound public let displayPreviews: PeerNotificationDisplayPreviews - public let storiesMuted: Bool? + public let storySettings: PeerStoryNotificationSettings public static var defaultSettings: TelegramPeerNotificationSettings { - return TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storiesMuted: nil) + return TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storySettings: PeerStoryNotificationSettings.default) } public func isRemovedFromTotalUnreadCount(`default`: Bool) -> Bool { switch self.muteState { - case .unmuted: - return false - case .muted: - return true - case .default: - return `default` + case .unmuted: + return false + case .muted: + return true + case .default: + return `default` } } @@ -417,18 +483,18 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, C } } - public init(muteState: PeerMuteState, messageSound: PeerMessageSound, displayPreviews: PeerNotificationDisplayPreviews, storiesMuted: Bool?) { + public init(muteState: PeerMuteState, messageSound: PeerMessageSound, displayPreviews: PeerNotificationDisplayPreviews, storySettings: PeerStoryNotificationSettings) { self.muteState = muteState self.messageSound = messageSound self.displayPreviews = displayPreviews - self.storiesMuted = storiesMuted + self.storySettings = storySettings } public init(decoder: PostboxDecoder) { self.muteState = PeerMuteState.decodeInline(decoder) self.messageSound = PeerMessageSound.decodeInline(decoder) self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder) - self.storiesMuted = decoder.decodeOptionalBoolForKey("stm") + self.storySettings = decoder.decode(PeerStoryNotificationSettings.self, forKey: "stor") ?? PeerStoryNotificationSettings.default } public init(from decoder: Decoder) throws { @@ -437,7 +503,7 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, C self.muteState = try container.decode(PeerMuteState.self, forKey: "muteState") self.messageSound = try container.decode(PeerMessageSound.self, forKey: "messageSound") self.displayPreviews = try container.decode(PeerNotificationDisplayPreviews.self, forKey: "displayPreviews") - self.storiesMuted = try? container.decodeIfPresent(Bool.self, forKey: "stm") + self.storySettings = try container.decodeIfPresent(PeerStoryNotificationSettings.self, forKey: "stor") ?? PeerStoryNotificationSettings.default } public func encode(to encoder: Encoder) throws { @@ -446,18 +512,14 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, C try container.encode(self.muteState, forKey: "muteState") try container.encode(self.messageSound, forKey: "messageSound") try container.encode(self.displayPreviews, forKey: "displayPreviews") - try container.encodeIfPresent(self.storiesMuted, forKey: "stm") + try container.encode(self.storySettings, forKey: "stor") } public func encode(_ encoder: PostboxEncoder) { self.muteState.encodeInline(encoder) self.messageSound.encodeInline(encoder) self.displayPreviews.encodeInline(encoder) - if let storiesMuted = self.storiesMuted { - encoder.encodeBool(storiesMuted, forKey: "stm") - } else { - encoder.encodeNil(forKey: "stm") - } + encoder.encode(self.storySettings, forKey: "stor") } public func isEqual(to: PeerNotificationSettings) -> Bool { @@ -469,22 +531,22 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, C } public func withUpdatedMuteState(_ muteState: PeerMuteState) -> TelegramPeerNotificationSettings { - return TelegramPeerNotificationSettings(muteState: muteState, messageSound: self.messageSound, displayPreviews: self.displayPreviews, storiesMuted: self.storiesMuted) + return TelegramPeerNotificationSettings(muteState: muteState, messageSound: self.messageSound, displayPreviews: self.displayPreviews, storySettings: self.storySettings) } public func withUpdatedMessageSound(_ messageSound: PeerMessageSound) -> TelegramPeerNotificationSettings { - return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: messageSound, displayPreviews: self.displayPreviews, storiesMuted: self.storiesMuted) + return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: messageSound, displayPreviews: self.displayPreviews, storySettings: self.storySettings) } public func withUpdatedDisplayPreviews(_ displayPreviews: PeerNotificationDisplayPreviews) -> TelegramPeerNotificationSettings { - return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: self.messageSound, displayPreviews: displayPreviews, storiesMuted: self.storiesMuted) + return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: self.messageSound, displayPreviews: displayPreviews, storySettings: self.storySettings) } - public func withUpdatedStoriesMuted(_ storiesMuted: Bool?) -> TelegramPeerNotificationSettings { - return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: self.messageSound, displayPreviews: self.displayPreviews, storiesMuted: storiesMuted) + public func withUpdatedStorySettings(_ storySettings: PeerStoryNotificationSettings) -> TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: self.messageSound, displayPreviews: self.displayPreviews, storySettings: storySettings) } public static func ==(lhs: TelegramPeerNotificationSettings, rhs: TelegramPeerNotificationSettings) -> Bool { - return lhs.muteState == rhs.muteState && lhs.messageSound == rhs.messageSound && lhs.displayPreviews == rhs.displayPreviews && lhs.storiesMuted == rhs.storiesMuted + return lhs.muteState == rhs.muteState && lhs.messageSound == rhs.messageSound && lhs.displayPreviews == rhs.displayPreviews && lhs.storySettings == rhs.storySettings } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift index 61d44d999b..73031b00fe 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift @@ -254,6 +254,44 @@ public extension TelegramEngine { } } + public func subscribe< + T0: TelegramEngineDataItem, + T1: TelegramEngineDataItem, + T2: TelegramEngineDataItem, + T3: TelegramEngineDataItem, + T4: TelegramEngineDataItem + >( + _ t0: T0, + _ t1: T1, + _ t2: T2, + _ t3: T3, + _ t4: T4 + ) -> Signal< + ( + T0.Result, + T1.Result, + T2.Result, + T3.Result, + T4.Result + ), + NoError> { + return self._subscribe(items: [ + t0 as! AnyPostboxViewDataItem, + t1 as! AnyPostboxViewDataItem, + t2 as! AnyPostboxViewDataItem, + t3 as! AnyPostboxViewDataItem, + t4 as! AnyPostboxViewDataItem + ]) + |> map { results -> (T0.Result, T1.Result, T2.Result, T3.Result, T4.Result) in + return ( + results[0] as! T0.Result, + results[1] as! T1.Result, + results[2] as! T2.Result, + results[3] as! T3.Result, + results[4] as! T4.Result + ) + } + } public func get< T0: TelegramEngineDataItem, @@ -308,5 +346,29 @@ public extension TelegramEngine { NoError> { return self.subscribe(t0, t1, t2, t3) |> take(1) } + + public func get< + T0: TelegramEngineDataItem, + T1: TelegramEngineDataItem, + T2: TelegramEngineDataItem, + T3: TelegramEngineDataItem, + T4: TelegramEngineDataItem + >( + _ t0: T0, + _ t1: T1, + _ t2: T2, + _ t3: T3, + _ t4: T4 + ) -> Signal< + ( + T0.Result, + T1.Result, + T2.Result, + T3.Result, + T4.Result + ), + NoError> { + return self.subscribe(t0, t1, t2, t3, t4) |> take(1) + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift index 2c9007e6cc..6ce2c4976c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift @@ -62,6 +62,20 @@ func _internal_togglePeerMuted(account: Account, peerId: PeerId, threadId: Int64 } } +public func resolvedAreStoriesMuted(globalSettings: GlobalNotificationSettingsSet, peer: Peer, peerSettings: TelegramPeerNotificationSettings?) -> Bool { + let defaultIsMuted = globalSettings.privateChats.storySettings.mute == .muted + switch peerSettings?.storySettings.mute { + case .none: + return defaultIsMuted + case .muted: + return true + case .unmuted: + return false + default: + return defaultIsMuted + } +} + func _internal_togglePeerStoriesMuted(account: Account, peerId: PeerId) -> Signal { return account.postbox.transaction { transaction -> Void in guard let peer = transaction.getPeer(peerId) else { @@ -82,12 +96,22 @@ func _internal_togglePeerStoriesMuted(account: Account, peerId: PeerId) -> Signa } let updatedSettings: TelegramPeerNotificationSettings - if let previousStoriesMuted = previousSettings.storiesMuted { - updatedSettings = previousSettings.withUpdatedStoriesMuted(!previousStoriesMuted) - } else { - updatedSettings = previousSettings.withUpdatedStoriesMuted(true) + var storySettings = previousSettings.storySettings + switch previousSettings.storySettings.mute { + case .default: + let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings + + if resolvedAreStoriesMuted(globalSettings: globalNotificationSettings.effective, peer: peer, peerSettings: previousSettings) { + storySettings.mute = .unmuted + } else { + storySettings.mute = .muted + } + case .unmuted: + storySettings.mute = .muted + case .muted: + storySettings.mute = .unmuted } - + updatedSettings = previousSettings.withUpdatedStorySettings(storySettings) transaction.updatePendingPeerNotificationSettings(peerId: notificationPeerId, settings: updatedSettings) } } @@ -213,13 +237,13 @@ func _internal_updatePeerDisplayPreviewsSetting(account: Account, transaction: T } } -func _internal_updatePeerStoriesMutedSetting(account: Account, peerId: PeerId, isMuted: Bool?) -> Signal { +func _internal_updatePeerStoriesMutedSetting(account: Account, peerId: PeerId, mute: PeerStoryNotificationSettings.Mute) -> Signal { return account.postbox.transaction { transaction -> Void in - _internal_updatePeerStoriesMutedSetting(account: account, transaction: transaction, peerId: peerId, isMuted: isMuted) + _internal_updatePeerStoriesMutedSetting(account: account, transaction: transaction, peerId: peerId, mute: mute) } } -func _internal_updatePeerStoriesMutedSetting(account: Account, transaction: Transaction, peerId: PeerId, isMuted: Bool?) { +func _internal_updatePeerStoriesMutedSetting(account: Account, transaction: Transaction, peerId: PeerId, mute: PeerStoryNotificationSettings.Mute) { if let peer = transaction.getPeer(peerId) { var notificationPeerId = peerId if let associatedPeerId = peer.associatedPeerId { @@ -234,7 +258,31 @@ func _internal_updatePeerStoriesMutedSetting(account: Account, transaction: Tran previousSettings = TelegramPeerNotificationSettings.defaultSettings } - let updatedSettings = previousSettings.withUpdatedStoriesMuted(isMuted) + var storySettings = previousSettings.storySettings + storySettings.mute = mute + let updatedSettings = previousSettings.withUpdatedStorySettings(storySettings) + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } +} + +func _internal_updatePeerStoriesHideSenderSetting(account: Account, transaction: Transaction, peerId: PeerId, hideSender: PeerStoryNotificationSettings.HideSender) { + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + var storySettings = previousSettings.storySettings + storySettings.hideSender = hideSender + let updatedSettings = previousSettings.withUpdatedStorySettings(storySettings) transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) } } @@ -279,3 +327,25 @@ func _internal_updatePeerNotificationSoundInteractive(account: Account, transact } } } + +func _internal_updatePeerStoryNotificationSoundInteractive(account: Account, transaction: Transaction, peerId: PeerId, sound: PeerMessageSound) { + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + var storySettings = previousSettings.storySettings + storySettings.sound = sound + let updatedSettings = previousSettings.withUpdatedStorySettings(storySettings) + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationExceptionsList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationExceptionsList.swift index b2c6c17892..96ab021bc3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationExceptionsList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationExceptionsList.swift @@ -19,7 +19,11 @@ public final class NotificationExceptionsList: Equatable { } func _internal_notificationExceptionsList(postbox: Postbox, network: Network) -> Signal { - return network.request(Api.functions.account.getNotifyExceptions(flags: 1 << 1, peer: nil)) + var flags: Int32 = 0 + flags |= 1 << 1 + flags |= 1 << 2 + + return network.request(Api.functions.account.getNotifyExceptions(flags: flags, peer: nil)) |> retryRequest |> mapToSignal { result -> Signal in return postbox.transaction { transaction -> NotificationExceptionsList in diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift index c82fbd6cbd..16eafaf8af 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift @@ -84,22 +84,24 @@ public enum EnginePeer: Equatable { case show case hide } + + public typealias StorySettigs = PeerStoryNotificationSettings public var muteState: MuteState public var messageSound: MessageSound public var displayPreviews: DisplayPreviews - public var storiesMuted: Bool? + public var storySettings: StorySettigs public init( muteState: MuteState, messageSound: MessageSound, displayPreviews: DisplayPreviews, - storiesMuted: Bool? + storySettings: StorySettigs ) { self.muteState = muteState self.messageSound = messageSound self.displayPreviews = displayPreviews - self.storiesMuted = storiesMuted + self.storySettings = storySettings } } @@ -219,13 +221,13 @@ public struct EngineGlobalNotificationSettings: Equatable { public var enabled: Bool public var displayPreviews: Bool public var sound: EnginePeer.NotificationSettings.MessageSound - public var storiesMuted: Bool + public var storySettings: EnginePeer.NotificationSettings.StorySettigs - public init(enabled: Bool, displayPreviews: Bool, sound: EnginePeer.NotificationSettings.MessageSound, storiesMuted: Bool) { + public init(enabled: Bool, displayPreviews: Bool, sound: EnginePeer.NotificationSettings.MessageSound, storySettings: EnginePeer.NotificationSettings.StorySettigs) { self.enabled = enabled self.displayPreviews = displayPreviews self.sound = sound - self.storiesMuted = storiesMuted + self.storySettings = storySettings } } @@ -333,7 +335,7 @@ public extension EnginePeer.NotificationSettings { muteState: MuteState(notificationSettings.muteState), messageSound: MessageSound(notificationSettings.messageSound), displayPreviews: DisplayPreviews(notificationSettings.displayPreviews), - storiesMuted: notificationSettings.storiesMuted + storySettings: notificationSettings.storySettings ) } @@ -342,7 +344,7 @@ public extension EnginePeer.NotificationSettings { muteState: self.muteState._asMuteState(), messageSound: self.messageSound._asMessageSound(), displayPreviews: self.displayPreviews._asDisplayPreviews(), - storiesMuted: self.storiesMuted + storySettings: self.storySettings ) } } @@ -602,7 +604,7 @@ public extension EngineGlobalNotificationSettings.CategorySettings { enabled: categorySettings.enabled, displayPreviews: categorySettings.displayPreviews, sound: EnginePeer.NotificationSettings.MessageSound(categorySettings.sound), - storiesMuted: categorySettings.storiesMuted ?? false + storySettings: categorySettings.storySettings ) } @@ -611,7 +613,7 @@ public extension EngineGlobalNotificationSettings.CategorySettings { enabled: self.enabled, displayPreviews: self.displayPreviews, sound: self.sound._asMessageSound(), - storiesMuted: self.storiesMuted + storySettings: self.storySettings ) } } @@ -625,4 +627,13 @@ public extension EngineGlobalNotificationSettings { contactsJoined: globalNotificationSettings.contactsJoined ) } + + func _asGlobalNotificationSettings() -> GlobalNotificationSettingsSet { + return GlobalNotificationSettingsSet( + privateChats: self.privateChats._asMessageNotificationSettings(), + groupChats: self.groupChats._asMessageNotificationSettings(), + channels: self.channels._asMessageNotificationSettings(), + contactsJoined: self.contactsJoined + ) + } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index d6ffec8417..44851be0a7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -273,8 +273,20 @@ public extension TelegramEngine { return _internal_updatePeerDisplayPreviewsSetting(account: self.account, peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) } - public func updatePeerStoriesMutedSetting(peerId: PeerId, isMuted: Bool?) -> Signal { - return _internal_updatePeerStoriesMutedSetting(account: self.account, peerId: peerId, isMuted: isMuted) + public func updatePeerStoriesMutedSetting(peerId: PeerId, mute: PeerStoryNotificationSettings.Mute) -> Signal { + return _internal_updatePeerStoriesMutedSetting(account: self.account, peerId: peerId, mute: mute) + } + + public func updatePeerStoriesHideSenderSetting(peerId: PeerId, hideSender: PeerStoryNotificationSettings.HideSender) -> Signal { + return self.account.postbox.transaction { transaction -> Void in + _internal_updatePeerStoriesHideSenderSetting(account: self.account, transaction: transaction, peerId: peerId, hideSender: hideSender) + } + } + + public func updatePeerStorySoundInteractive(peerId: PeerId, sound: PeerMessageSound) -> Signal { + return self.account.postbox.transaction { transaction -> Void in + _internal_updatePeerStoryNotificationSoundInteractive(account: self.account, transaction: transaction, peerId: peerId, sound: sound) + } } public func updatePeerNotificationSoundInteractive(peerId: PeerId, threadId: Int64?, sound: PeerMessageSound) -> Signal { @@ -306,7 +318,9 @@ public extension TelegramEngine { public func removeCustomStoryNotificationSettings(peerIds: [PeerId]) -> Signal { return self.account.postbox.transaction { transaction -> Void in for peerId in peerIds { - _internal_updatePeerStoriesMutedSetting(account: self.account, transaction: transaction, peerId: peerId, isMuted: nil) + _internal_updatePeerStoriesMutedSetting(account: self.account, transaction: transaction, peerId: peerId, mute: .default) + _internal_updatePeerStoriesHideSenderSetting(account: self.account, transaction: transaction, peerId: peerId, hideSender: .default) + _internal_updatePeerStoryNotificationSoundInteractive(account: self.account, transaction: transaction, peerId: peerId, sound: .default) } } |> ignoreValues diff --git a/submodules/TelegramUI/Components/NotificationExceptionsScreen/Sources/NotificationExceptionsScreen.swift b/submodules/TelegramUI/Components/NotificationExceptionsScreen/Sources/NotificationExceptionsScreen.swift index 5572e2434e..68fb59d54b 100644 --- a/submodules/TelegramUI/Components/NotificationExceptionsScreen/Sources/NotificationExceptionsScreen.swift +++ b/submodules/TelegramUI/Components/NotificationExceptionsScreen/Sources/NotificationExceptionsScreen.swift @@ -496,7 +496,9 @@ public func threadNotificationExceptionsScreen(context: AccountContext, peerId: } updated(stateValue.with({ $0 }).notificationExceptions) }) - }, updatePeerStoryNotifications: { _, _ in + }, updatePeerStoriesMuted: { _, _ in + }, updatePeerStoriesHideSender: { _, _ in + }, updatePeerStorySound: { _, _ in }, removePeerFromExceptions: { let _ = context.engine.peers.removeCustomThreadNotificationSettings(peerId: peerId, threadIds: [item.threadId]).start() updateState { current in diff --git a/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift b/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift index b7dd896922..1a9968dfd6 100644 --- a/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift +++ b/submodules/TelegramUI/Components/NotificationPeerExceptionController/Sources/NotificationPeerExceptionController.swift @@ -123,7 +123,7 @@ public enum NotificationExceptionMode : Equatable { case .default: break default: - values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .default, messageSound: sound, displayPreviews: .default, storiesMuted: nil), peer: peer, date: Date().timeIntervalSince1970) + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .default, messageSound: sound, displayPreviews: .default, storySettings: .default), peer: peer, date: Date().timeIntervalSince1970) } } return values @@ -161,7 +161,7 @@ public enum NotificationExceptionMode : Equatable { case .default: break default: - values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: muteState, messageSound: .default, displayPreviews: .default, storiesMuted: nil), peer: peer, date: Date().timeIntervalSince1970) + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: muteState, messageSound: .default, displayPreviews: .default, storySettings: .default), peer: peer, date: Date().timeIntervalSince1970) } } return values @@ -215,7 +215,7 @@ public enum NotificationExceptionMode : Equatable { case .default: break default: - values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: displayPreviews, storiesMuted: nil), peer: peer, date: Date().timeIntervalSince1970) + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: displayPreviews, storySettings: .default), peer: peer, date: Date().timeIntervalSince1970) } } return values @@ -233,32 +233,38 @@ public enum NotificationExceptionMode : Equatable { } } - public func withUpdatedPeerStoryNotifications(_ peer: EnginePeer, _ storyNotifications: PeerNotificationDisplayPreviews) -> NotificationExceptionMode { - let apply:([EnginePeer.Id : NotificationExceptionWrapper], EnginePeer.Id, PeerNotificationDisplayPreviews) -> [EnginePeer.Id : NotificationExceptionWrapper] = { values, peerId, storyNotifications in - let storiesMuted: Bool? - switch storyNotifications { - case .default: - storiesMuted = nil - case .show: - storiesMuted = false - case .hide: - storiesMuted = true - } - + public func withUpdatedPeerStoriesMuted(_ peer: EnginePeer, _ mute: PeerStoryNotificationSettings.Mute) -> NotificationExceptionMode { + let apply:([EnginePeer.Id : NotificationExceptionWrapper], EnginePeer.Id, PeerStoryNotificationSettings.Mute) -> [EnginePeer.Id : NotificationExceptionWrapper] = { values, peerId, mute in var values = values if let value = values[peerId] { - switch storyNotifications { + switch mute { case .default: - values.removeValue(forKey: peerId) + switch value.settings.storySettings.mute { + case .default: + //values.removeValue(forKey: peerId) + break + default: + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.mute = mute + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) + } default: - values[peerId] = value.updateSettings({$0.withUpdatedStoriesMuted(storiesMuted)}).withUpdatedDate(Date().timeIntervalSince1970) + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.mute = mute + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) } } else { - switch storyNotifications { + switch mute { case .default: break default: - values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storiesMuted: storiesMuted), peer: peer, date: Date().timeIntervalSince1970) + var updatedSettings = PeerStoryNotificationSettings.default + updatedSettings.mute = mute + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storySettings: updatedSettings), peer: peer, date: Date().timeIntervalSince1970) } } return values @@ -266,7 +272,97 @@ public enum NotificationExceptionMode : Equatable { switch self { case let .stories(values): - return .stories(apply(values, peer.id, storyNotifications)) + return .stories(apply(values, peer.id, mute)) + default: + return self + } + } + + public func withUpdatedPeerStoriesHideSender(_ peer: EnginePeer, _ hideSender: PeerStoryNotificationSettings.HideSender) -> NotificationExceptionMode { + let apply:([EnginePeer.Id : NotificationExceptionWrapper], EnginePeer.Id, PeerStoryNotificationSettings.HideSender) -> [EnginePeer.Id : NotificationExceptionWrapper] = { values, peerId, hideSender in + var values = values + if let value = values[peerId] { + switch hideSender { + case .default: + switch value.settings.storySettings.hideSender { + case .default: + //values.removeValue(forKey: peerId) + break + default: + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.hideSender = hideSender + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) + } + default: + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.hideSender = hideSender + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) + } + } else { + switch hideSender { + case .default: + break + default: + var updatedSettings = PeerStoryNotificationSettings.default + updatedSettings.hideSender = hideSender + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storySettings: updatedSettings), peer: peer, date: Date().timeIntervalSince1970) + } + } + return values + } + + switch self { + case let .stories(values): + return .stories(apply(values, peer.id, hideSender)) + default: + return self + } + } + + public func withUpdatedPeerStorySound(_ peer: EnginePeer, _ sound: PeerMessageSound) -> NotificationExceptionMode { + let apply:([EnginePeer.Id : NotificationExceptionWrapper], EnginePeer.Id, PeerMessageSound) -> [EnginePeer.Id : NotificationExceptionWrapper] = { values, peerId, sound in + var values = values + if let value = values[peerId] { + switch sound { + case .default: + switch value.settings.storySettings.sound { + case .default: + //values.removeValue(forKey: peerId) + break + default: + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.sound = sound + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) + } + default: + values[peerId] = value.updateSettings({ + var updatedSettings = $0.storySettings + updatedSettings.sound = sound + return $0.withUpdatedStorySettings(updatedSettings) + }).withUpdatedDate(Date().timeIntervalSince1970) + } + } else { + switch sound { + case .default: + break + default: + var updatedSettings = PeerStoryNotificationSettings.default + updatedSettings.sound = sound + values[peerId] = NotificationExceptionWrapper(settings: TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default, storySettings: updatedSettings), peer: peer, date: Date().timeIntervalSince1970) + } + } + return values + } + + switch self { + case let .stories(values): + return .stories(apply(values, peer.id, sound)) default: return self } @@ -308,6 +404,7 @@ private enum NotificationPeerExceptionEntryId: Hashable { case sound(PeerMessageSound.Id) case switcherHeader case displayPreviews(NotificationPeerExceptionSwitcher) + case showSender(NotificationPeerExceptionSwitcher) case displayPreviewsHeader case storyNotifications(NotificationPeerExceptionSwitcher) case storyNotificationsHeader @@ -326,19 +423,36 @@ private final class NotificationPeerExceptionArguments { let selectSound: (PeerMessageSound) -> Void let selectMode: (NotificationPeerExceptionSwitcher) -> Void let selectDisplayPreviews: (NotificationPeerExceptionSwitcher) -> Void - let selectStoryNotifications: (NotificationPeerExceptionSwitcher) -> Void + let selectStoriesMuted: (NotificationPeerExceptionSwitcher) -> Void + let selectHideStoriesSender: (NotificationPeerExceptionSwitcher) -> Void + let selectStorySound: (PeerMessageSound) -> Void let removeFromExceptions: () -> Void let complete: () -> Void let cancel: () -> Void let upload: () -> Void let deleteSound: (PeerMessageSound, String) -> Void - init(account: Account, selectSound: @escaping(PeerMessageSound) -> Void, selectMode: @escaping(NotificationPeerExceptionSwitcher) -> Void, selectDisplayPreviews: @escaping (NotificationPeerExceptionSwitcher) -> Void, selectStoryNotifications: @escaping (NotificationPeerExceptionSwitcher) -> Void, removeFromExceptions: @escaping () -> Void, complete: @escaping()->Void, cancel: @escaping() -> Void, upload: @escaping () -> Void, deleteSound: @escaping (PeerMessageSound, String) -> Void) { + init( + account: Account, + selectSound: @escaping(PeerMessageSound) -> Void, + selectMode: @escaping(NotificationPeerExceptionSwitcher) -> Void, + selectDisplayPreviews: @escaping (NotificationPeerExceptionSwitcher) -> Void, + selectStoriesMuted: @escaping (NotificationPeerExceptionSwitcher) -> Void, + selectHideStoriesSender: @escaping (NotificationPeerExceptionSwitcher) -> Void, + selectStorySound: @escaping (PeerMessageSound) -> Void, + removeFromExceptions: @escaping () -> Void, + complete: @escaping() -> Void, + cancel: @escaping() -> Void, + upload: @escaping () -> Void, + deleteSound: @escaping (PeerMessageSound, String) -> Void + ) { self.account = account self.selectSound = selectSound self.selectMode = selectMode self.selectDisplayPreviews = selectDisplayPreviews - self.selectStoryNotifications = selectStoryNotifications + self.selectStoriesMuted = selectStoriesMuted + self.selectHideStoriesSender = selectHideStoriesSender + self.selectStorySound = selectStorySound self.removeFromExceptions = removeFromExceptions self.complete = complete self.cancel = cancel @@ -355,6 +469,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { case switcher(index:Int32, theme: PresentationTheme, strings: PresentationStrings, mode: NotificationPeerExceptionSwitcher, selected: Bool) case switcherHeader(index:Int32, theme: PresentationTheme, title: String) case displayPreviews(index:Int32, theme: PresentationTheme, strings: PresentationStrings, value: NotificationPeerExceptionSwitcher, selected: Bool) + case showSender(index:Int32, theme: PresentationTheme, strings: PresentationStrings, value: NotificationPeerExceptionSwitcher, selected: Bool) case displayPreviewsHeader(index:Int32, theme: PresentationTheme, title: String) case storyNotifications(index:Int32, theme: PresentationTheme, strings: PresentationStrings, value: NotificationPeerExceptionSwitcher, selected: Bool) case storyNotificationsHeader(index:Int32, theme: PresentationTheme, title: String) @@ -379,6 +494,8 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { return index case let .displayPreviews(index, _, _, _, _): return index + case let .showSender(index, _, _, _, _): + return index case let .storyNotificationsHeader(index, _, _): return index case let .storyNotifications(index, _, _, _, _): @@ -408,7 +525,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { return NotificationPeerExceptionSection.remove.rawValue case .switcher, .switcherHeader: return NotificationPeerExceptionSection.switcher.rawValue - case .displayPreviews, .displayPreviewsHeader: + case .displayPreviews, .displayPreviewsHeader, .showSender: return NotificationPeerExceptionSection.displayPreviews.rawValue case .storyNotifications, .storyNotificationsHeader: return NotificationPeerExceptionSection.storyNotifications.rawValue @@ -439,6 +556,8 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { return .displayPreviews(mode) case .displayPreviewsHeader: return .displayPreviewsHeader + case let .showSender(_, _, _, mode, _): + return .showSender(mode) case let .storyNotifications(_, _, _, mode, _): return .storyNotifications(mode) case .storyNotificationsHeader: @@ -497,6 +616,17 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { arguments.selectDisplayPreviews(value) }) + case let .showSender(_, _, strings, value, selected): + let title: String + switch value { + case .alwaysOn: + title = strings.Notification_Exceptions_MessagePreviewAlwaysOn + case .alwaysOff: + title = strings.Notification_Exceptions_MessagePreviewAlwaysOff + } + return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { + arguments.selectHideStoriesSender(value) + }) case let .cloudHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .cloudInfo(_, text): @@ -517,7 +647,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { title = strings.Notification_Exceptions_MessagePreviewAlwaysOff } return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { - arguments.selectStoryNotifications(value) + arguments.selectStoriesMuted(value) }) case let .storyNotificationsHeader(_, _, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) @@ -545,7 +675,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { private func notificationPeerExceptionEntries(presentationData: PresentationData, peer: EnginePeer?, notificationSoundList: NotificationSoundList?, state: NotificationExceptionPeerState, isStories: Bool?) -> [NotificationPeerExceptionEntry] { - let selectedSound = resolvedNotificationSound(sound: state.selectedSound, notificationSoundList: notificationSoundList) + let selectedSound = resolvedNotificationSound(sound: isStories == true ? state.selectedStoriesSound : state.selectedSound, notificationSoundList: notificationSoundList) var entries: [NotificationPeerExceptionEntry] = [] @@ -580,14 +710,31 @@ private func notificationPeerExceptionEntries(presentationData: PresentationData //TODO:localize entries.append(.storyNotificationsHeader(index: index, theme: presentationData.theme, title: "STORY NOTIFICATIONS")) index += 1 - entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storyNotifications == .alwaysOn)) + entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesMuted == .alwaysOn)) index += 1 - entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOff, selected: state.storyNotifications == .alwaysOff)) + entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOff, selected: state.storiesMuted == .alwaysOff)) index += 1 + + if state.storiesMuted != .alwaysOff { + entries.append(.displayPreviewsHeader(index: index, theme: presentationData.theme, title: "Display Author Name")) + index += 1 + entries.append(.showSender(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesHideSender == .alwaysOn)) + index += 1 + entries.append(.showSender(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOff, selected: state.storiesHideSender == .alwaysOff)) + index += 1 + } } } - if isStories == nil || isStories == false { + var displaySounds = true + + if isStories == true { + if state.storiesMuted == .alwaysOff { + displaySounds = false + } + } + + if displaySounds { entries.append(.cloudHeader(index: index, text: presentationData.strings.Notifications_TelegramTones)) index += 1 @@ -650,7 +797,9 @@ private struct NotificationExceptionPeerState : Equatable { var mode: NotificationPeerExceptionSwitcher var defaultSound: PeerMessageSound var displayPreviews: NotificationPeerExceptionSwitcher - var storyNotifications: NotificationPeerExceptionSwitcher + var storiesMuted: NotificationPeerExceptionSwitcher + var selectedStoriesSound: PeerMessageSound + var storiesHideSender: NotificationPeerExceptionSwitcher var removedSounds: [PeerMessageSound] init(canRemove: Bool, notifications: TelegramPeerNotificationSettings? = nil) { @@ -665,30 +814,64 @@ private struct NotificationExceptionPeerState : Equatable { self.mode = .alwaysOn } self.displayPreviews = notifications.displayPreviews == .hide ? .alwaysOff : .alwaysOn - self.storyNotifications = notifications.storiesMuted == true ? .alwaysOff : .alwaysOn + self.storiesMuted = notifications.storySettings.mute == .muted ? .alwaysOff : .alwaysOn + self.selectedStoriesSound = notifications.storySettings.sound + self.storiesHideSender = notifications.storySettings.hideSender == .hide ? .alwaysOff : .alwaysOn } else { self.selectedSound = .default self.mode = .alwaysOn self.displayPreviews = .alwaysOn - self.storyNotifications = .alwaysOn + self.storiesMuted = PeerStoryNotificationSettings.default.mute == .muted ? .alwaysOff : .alwaysOn + self.selectedStoriesSound = PeerStoryNotificationSettings.default.sound + self.storiesHideSender = PeerStoryNotificationSettings.default.hideSender == .hide ? .alwaysOff : .alwaysOn } self.defaultSound = .default self.removedSounds = [] } - init(canRemove: Bool, selectedSound: PeerMessageSound, mode: NotificationPeerExceptionSwitcher, defaultSound: PeerMessageSound, displayPreviews: NotificationPeerExceptionSwitcher, storyNotifications: NotificationPeerExceptionSwitcher, removedSounds: [PeerMessageSound]) { + init( + canRemove: Bool, + selectedSound: PeerMessageSound, + mode: NotificationPeerExceptionSwitcher, + defaultSound: PeerMessageSound, + displayPreviews: NotificationPeerExceptionSwitcher, + storiesMuted: NotificationPeerExceptionSwitcher, + selectedStoriesSound: PeerMessageSound, + storiesHideSender: NotificationPeerExceptionSwitcher, + removedSounds: [PeerMessageSound] + ) { self.canRemove = canRemove self.selectedSound = selectedSound self.mode = mode self.defaultSound = defaultSound self.displayPreviews = displayPreviews - self.storyNotifications = storyNotifications + self.storiesMuted = storiesMuted + self.selectedStoriesSound = selectedStoriesSound + self.storiesHideSender = storiesHideSender self.removedSounds = removedSounds } } -public func notificationPeerExceptionController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, customTitle: String? = nil, threadId: Int64?, isStories: Bool?, canRemove: Bool, defaultSound: PeerMessageSound, edit: Bool = false, updatePeerSound: @escaping(EnginePeer.Id, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(EnginePeer.Id, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(EnginePeer.Id, PeerNotificationDisplayPreviews) -> Void, updatePeerStoryNotifications: @escaping(EnginePeer.Id, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController { +public func notificationPeerExceptionController( + context: AccountContext, + updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, + peer: EnginePeer, + customTitle: String? = nil, + threadId: Int64?, + isStories: Bool?, + canRemove: Bool, + defaultSound: PeerMessageSound, + edit: Bool = false, + updatePeerSound: @escaping(EnginePeer.Id, PeerMessageSound) -> Void, + updatePeerNotificationInterval: @escaping(EnginePeer.Id, Int32?) -> Void, + updatePeerDisplayPreviews: @escaping(EnginePeer.Id, PeerNotificationDisplayPreviews) -> Void, + updatePeerStoriesMuted: @escaping(EnginePeer.Id, PeerStoryNotificationSettings.Mute) -> Void, + updatePeerStoriesHideSender: @escaping (EnginePeer.Id, PeerStoryNotificationSettings.HideSender) -> Void, + updatePeerStorySound: @escaping (EnginePeer.Id, PeerMessageSound) -> Void, + removePeerFromExceptions: @escaping () -> Void, + modifiedPeer: @escaping () -> Void +) -> ViewController { let initialState = NotificationExceptionPeerState(canRemove: false) let statePromise = Promise(initialState) let stateValue = Atomic(value: initialState) @@ -706,16 +889,30 @@ public func notificationPeerExceptionController(context: AccountContext, updated let soundActionDisposable = MetaDisposable() let arguments = NotificationPeerExceptionArguments(account: context.account, selectSound: { sound in - updateState { state in - let _ = (context.engine.peers.notificationSoundList() - |> take(1) - |> deliverOnMainQueue).start(next: { notificationSoundList in - playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: state.defaultSound).start()) - }) - - var state = state - state.selectedSound = sound - return state + if isStories == true { + updateState { state in + let _ = (context.engine.peers.notificationSoundList() + |> take(1) + |> deliverOnMainQueue).start(next: { notificationSoundList in + playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: state.defaultSound).start()) + }) + + var state = state + state.selectedStoriesSound = sound + return state + } + } else { + updateState { state in + let _ = (context.engine.peers.notificationSoundList() + |> take(1) + |> deliverOnMainQueue).start(next: { notificationSoundList in + playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: state.defaultSound).start()) + }) + + var state = state + state.selectedSound = sound + return state + } } }, selectMode: { mode in updateState { state in @@ -729,10 +926,28 @@ public func notificationPeerExceptionController(context: AccountContext, updated state.displayPreviews = value return state } - }, selectStoryNotifications: { value in + }, selectStoriesMuted: { value in updateState { state in var state = state - state.storyNotifications = value + state.storiesMuted = value + return state + } + }, selectHideStoriesSender: { value in + updateState { state in + var state = state + state.storiesHideSender = value + return state + } + }, selectStorySound: { sound in + updateState { state in + let _ = (context.engine.peers.notificationSoundList() + |> take(1) + |> deliverOnMainQueue).start(next: { notificationSoundList in + playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: state.defaultSound).start()) + }) + + var state = state + state.selectedStoriesSound = sound return state } }, removeFromExceptions: { @@ -816,10 +1031,16 @@ public func notificationPeerExceptionController(context: AccountContext, updated |> take(1) |> deliverOnMainQueue).start(next: { notificationSoundList in updateState { state in - updatePeerSound(peer.id, resolvedNotificationSound(sound: state.selectedSound, notificationSoundList: notificationSoundList)) - updatePeerNotificationInterval(peer.id, state.mode == .alwaysOn ? 0 : Int32.max) - updatePeerDisplayPreviews(peer.id, state.displayPreviews == .alwaysOn ? .show : .hide) - updatePeerStoryNotifications(peer.id, state.storyNotifications == .alwaysOn ? .show : .hide) + if isStories == nil || isStories == false { + updatePeerSound(peer.id, resolvedNotificationSound(sound: state.selectedSound, notificationSoundList: notificationSoundList)) + updatePeerNotificationInterval(peer.id, state.mode == .alwaysOn ? 0 : Int32.max) + updatePeerDisplayPreviews(peer.id, state.displayPreviews == .alwaysOn ? .show : .hide) + } + if isStories == nil || isStories == true { + updatePeerStoriesMuted(peer.id, state.storiesMuted == .alwaysOn ? .unmuted : .muted) + updatePeerStoriesHideSender(peer.id, state.storiesHideSender == .alwaysOn ? .show : .hide) + updatePeerStorySound(peer.id, resolvedNotificationSound(sound: state.selectedStoriesSound, notificationSoundList: notificationSoundList)) + } return state } }) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift index a1792230e3..59a052caa3 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryChatContent.swift @@ -100,10 +100,10 @@ public final class StoryContentContextImpl: StoryContentContext { let additionalPeerData: StoryContentContextState.AdditionalPeerData if let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView, let cachedUserData = cachedPeerDataView.cachedPeerData as? CachedUserData { var isMuted = false - if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings, let storiesMuted = notificationSettings.storiesMuted { - isMuted = storiesMuted + if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings { + isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings) } else { - isMuted = globalNotificationSettings.privateChats.storiesMuted + isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: nil) } additionalPeerData = StoryContentContextState.AdditionalPeerData(isMuted: isMuted, areVoiceMessagesAvailable: cachedUserData.voiceMessagesAvailable) } else { @@ -913,13 +913,12 @@ public final class SingleStoryContentContextImpl: StoryContentContext { let (peer, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data let (item, peers) = itemAndPeers - var isMuted = false - if let storiesMuted = notificationSettings.storiesMuted { - isMuted = storiesMuted - } else { - isMuted = globalNotificationSettings.privateChats.storiesMuted + guard let peer else { + return } + let isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings()) + let additionalPeerData = StoryContentContextState.AdditionalPeerData( isMuted: isMuted, areVoiceMessagesAvailable: areVoiceMessagesAvailable @@ -934,7 +933,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext { } } - if let item, case let .item(itemValue) = item, let media = itemValue.media, let peer { + if let item, case let .item(itemValue) = item, let media = itemValue.media { let mappedItem = EngineStoryItem( id: itemValue.id, timestamp: itemValue.timestamp, @@ -1062,13 +1061,12 @@ public final class PeerStoryListContentContextImpl: StoryContentContext { let (peer, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data - var isMuted = false - if let storiesMuted = notificationSettings.storiesMuted { - isMuted = storiesMuted - } else { - isMuted = globalNotificationSettings.privateChats.storiesMuted + guard let peer else { + return } + let isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings()) + let additionalPeerData = StoryContentContextState.AdditionalPeerData( isMuted: isMuted, areVoiceMessagesAvailable: areVoiceMessagesAvailable @@ -1104,7 +1102,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext { } let stateValue: StoryContentContextState - if let focusedIndex = focusedIndex, let peer = peer { + if let focusedIndex = focusedIndex { let item = state.items[focusedIndex] self.focusedId = item.id @@ -1151,7 +1149,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext { var resultResources: [EngineMediaResource.Id: StoryPreloadInfo] = [:] var pollItems: [StoryKey] = [] - if let peer, let focusedIndex, let slice = stateValue.slice { + if let focusedIndex, let slice = stateValue.slice { var possibleItems: [(EnginePeer, EngineStoryItem)] = [] if peer.id == self.context.account.peerId { pollItems.append(StoryKey(peerId: peer.id, id: slice.item.storyItem.id)) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift index b04b13c021..204668ed82 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift @@ -138,7 +138,7 @@ final class StoryItemContentComponent: Component { loopVideo: true, enableSound: true, beginWithAmbientSound: environment.sharedState.useAmbientMode, - useLargeThumbnail: true, + useLargeThumbnail: false, autoFetchFullSizeThumbnail: true, tempFilePath: nil, captureProtected: component.item.isForwardingDisabled, @@ -429,7 +429,7 @@ final class StoryItemContentComponent: Component { userLocation: .other, videoReference: .story(peer: peerReference, id: component.item.id, media: file), onlyFullSize: false, - useLargeThumbnail: true, + useLargeThumbnail: false, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true, overlayColor: nil, diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index 7e9e93d07d..e31aadb307 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -3145,8 +3145,11 @@ public final class StoryItemSetContainerComponent: Component { guard let component = self.component else { return } - let _ = (component.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: component.slice.peer.id)) - |> deliverOnMainQueue).start(next: { [weak self] settings in + let _ = (component.context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: component.slice.peer.id), + TelegramEngine.EngineData.Item.NotificationSettings.Global() + ) + |> deliverOnMainQueue).start(next: { [weak self] settings, globalSettings in guard let self, let component = self.component, let controller = component.controller() else { return } @@ -3161,7 +3164,8 @@ public final class StoryItemSetContainerComponent: Component { let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) var items: [ContextMenuItem] = [] - let isMuted = settings.storiesMuted == true + let isMuted = resolvedAreStoriesMuted(globalSettings: globalSettings._asGlobalNotificationSettings(), peer: component.slice.peer._asPeer(), peerSettings: settings._asNotificationSettings()) + items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Don't Notify", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: component.slice.additionalPeerData.isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, a in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 981df1a615..0cce0d29bd 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -4712,17 +4712,18 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue } - let updatePeerStoryNotifications: (PeerId, PeerNotificationDisplayPreviews) -> Signal = { peerId, storyNotifications in - var isMuted: Bool? - switch storyNotifications { - case .default: - isMuted = nil - case .show: - isMuted = false - case .hide: - isMuted = true - } - return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, isMuted: isMuted) |> deliverOnMainQueue + let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal = { + peerId, mute in + return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue + } + + let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal = { + peerId, hideSender in + return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue + } + + let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal = { peerId, sound in + return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue } let mode: NotificationExceptionMode @@ -4775,11 +4776,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro |> deliverOnMainQueue).start(next: { _ in }) - }, updatePeerStoryNotifications: { peerId, storyNotifications in - let _ = (updatePeerStoryNotifications(peerId, storyNotifications) - |> deliverOnMainQueue).start(next: { _ in - - }) + }, updatePeerStoriesMuted: { peerId, mute in + let _ = (updatePeerStoriesMuted(peerId, mute) + |> deliverOnMainQueue).start() + }, updatePeerStoriesHideSender: { peerId, hideSender in + let _ = (updatePeerStoriesHideSender(peerId, hideSender) + |> deliverOnMainQueue).start() + }, updatePeerStorySound: { peerId, sound in + let _ = (updatePeerStorySound(peer.id, sound) + |> deliverOnMainQueue).start() }, removePeerFromExceptions: { }, modifiedPeer: { })