From 1d4d2b020443fd67f5ddf5678b176b94a8aab58b Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Sat, 10 Feb 2024 09:36:48 -0700 Subject: [PATCH] mute: integrate new MutelistManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is slightly large (I think still within the guidelines tho) , but also pretty straightforward. I thought for a while about how I could split this up in a straightforward way, and I couldn’t come up with anything without breaking intermediate builds. - Deleted a lot of old/unnecessary code (ie. the Collection extension for MuteItem, since we’re now using the MutelistManager sets) - Changed damus_state.contacts to damus_state.mutelist_manager for all mute list manager work - Updated MutelistView to take advantage of new code (this is probably the largest change in this patch) Lighting-Address: fishcharlie@strike.me Signed-off-by: Charlie Fish Reviewed-by: William Casarin Link: 20240210163650.42884-4-contact@charlie.fish Signed-off-by: William Casarin --- .../NotificationExtensionState.swift | 2 + damus/ContentView.swift | 9 +- damus/Models/Contacts.swift | 39 +------ damus/Models/ContentFilters.swift | 2 +- damus/Models/DamusState.swift | 7 +- damus/Models/HeadlessDamusState.swift | 1 + damus/Models/HomeModel.swift | 28 ++--- damus/Models/MuteItem.swift | 61 ---------- damus/Models/MutedThreadsManager.swift | 4 +- damus/Models/NotificationsManager.swift | 2 +- damus/Models/SearchHomeModel.swift | 4 +- damus/Models/SearchModel.swift | 4 +- damus/TestData.swift | 1 + damus/Util/Router.swift | 9 +- damus/Views/DMChatView.swift | 2 +- damus/Views/DirectMessagesView.swift | 4 +- damus/Views/Events/EventMenu.swift | 8 +- .../Events/EventMutingContainerView.swift | 8 +- damus/Views/Muting/AddMuteItemView.swift | 4 +- damus/Views/Muting/MutelistView.swift | 105 ++++++++++-------- damus/Views/Profile/ProfileView.swift | 6 +- damus/Views/SearchHomeView.swift | 2 +- damus/Views/SearchView.swift | 10 +- damus/Views/SideMenuView.swift | 2 +- 24 files changed, 123 insertions(+), 201 deletions(-) diff --git a/DamusNotificationService/NotificationExtensionState.swift b/DamusNotificationService/NotificationExtensionState.swift index 69acc020..d5cb989f 100644 --- a/DamusNotificationService/NotificationExtensionState.swift +++ b/DamusNotificationService/NotificationExtensionState.swift @@ -11,6 +11,7 @@ struct NotificationExtensionState: HeadlessDamusState { let ndb: Ndb let settings: UserSettingsStore let contacts: Contacts + let mutelist_manager: MutelistManager let keypair: Keypair let profiles: Profiles let zaps: Zaps @@ -27,6 +28,7 @@ struct NotificationExtensionState: HeadlessDamusState { self.settings = UserSettingsStore() self.contacts = Contacts(our_pubkey: keypair.pubkey) + self.mutelist_manager = MutelistManager() self.keypair = keypair self.profiles = Profiles(ndb: ndb) self.zaps = Zaps(our_pubkey: keypair.pubkey) diff --git a/damus/ContentView.swift b/damus/ContentView.swift index b7625afa..c10ce9c8 100644 --- a/damus/ContentView.swift +++ b/damus/ContentView.swift @@ -550,7 +550,7 @@ struct ContentView: View { return } - ds.contacts.set_mutelist(mutelist) + ds.mutelist_manager.set_mutelist(mutelist) ds.postbox.send(mutelist) confirm_overwrite_mutelist = false @@ -569,7 +569,7 @@ struct ContentView: View { return } - if ds.contacts.mutelist == nil { + if ds.mutelist_manager.event == nil { confirm_overwrite_mutelist = true } else { guard let keypair = ds.keypair.to_full(), @@ -578,11 +578,11 @@ struct ContentView: View { return } - guard let ev = create_or_update_mutelist(keypair: keypair, mprev: ds.contacts.mutelist, to_add: muting) else { + guard let ev = create_or_update_mutelist(keypair: keypair, mprev: ds.mutelist_manager.event, to_add: muting) else { return } - ds.contacts.set_mutelist(ev) + ds.mutelist_manager.set_mutelist(ev) ds.postbox.send(ev) } } @@ -660,6 +660,7 @@ struct ContentView: View { likes: EventCounter(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey), contacts: Contacts(our_pubkey: pubkey), + mutelist_manager: MutelistManager(), profiles: Profiles(ndb: ndb), dms: home.dms, previews: PreviewCache(), diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift index 28e11438..e411ef0d 100644 --- a/damus/Models/Contacts.swift +++ b/damus/Models/Contacts.swift @@ -13,51 +13,14 @@ class Contacts { private var friend_of_friends: Set = Set() /// Tracks which friends are friends of a given pubkey. private var pubkey_to_our_friends = [Pubkey : Set]() - private var muted: Set = Set() let our_pubkey: Pubkey var event: NostrEvent? - var mutelist: NostrEvent? - + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey } - - func is_muted(_ item: MuteItem) -> Bool { - return muted.contains(item) - } - func set_mutelist(_ ev: NostrEvent) { - let oldlist = self.mutelist - self.mutelist = ev - - let old: Set = oldlist?.mute_list ?? Set() - let new: Set = ev.mute_list ?? Set() - let diff = old.symmetricDifference(new) - - var new_mutes = Set() - var new_unmutes = Set() - - for d in diff { - if new.contains(d) { - new_mutes.insert(d) - } else { - new_unmutes.insert(d) - } - } - - // TODO: set local mutelist here - self.muted = ev.mute_list ?? Set() - - if new_mutes.count > 0 { - notify(.new_mutes(new_mutes)) - } - - if new_unmutes.count > 0 { - notify(.new_unmutes(new_unmutes)) - } - } - func remove_friend(_ pubkey: Pubkey) { friends.remove(pubkey) diff --git a/damus/Models/ContentFilters.swift b/damus/Models/ContentFilters.swift index c876f3b6..63a23a36 100644 --- a/damus/Models/ContentFilters.swift +++ b/damus/Models/ContentFilters.swift @@ -33,7 +33,7 @@ func get_repost_of_muted_user_filter(damus_state: DamusState) -> ((_ ev: NostrEv guard ev.known_kind == .boost else { return true } // This needs to use cached because it can be way too slow otherwise guard let inner_ev = ev.get_cached_inner_event(cache: damus_state.events) else { return true } - return should_show_event(contacts: damus_state.contacts, ev: inner_ev) + return should_show_event(state: damus_state, ev: inner_ev) } } diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift index 0b35abbf..32575bec 100644 --- a/damus/Models/DamusState.swift +++ b/damus/Models/DamusState.swift @@ -14,6 +14,7 @@ struct DamusState: HeadlessDamusState { let likes: EventCounter let boosts: EventCounter let contacts: Contacts + let mutelist_manager: MutelistManager let profiles: Profiles let dms: DirectMessagesModel let previews: PreviewCache @@ -34,13 +35,14 @@ struct DamusState: HeadlessDamusState { let video: VideoController let ndb: Ndb var purple: DamusPurple - - init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [String], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil) { + + init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [String], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil) { self.pool = pool self.keypair = keypair self.likes = likes self.boosts = boosts self.contacts = contacts + self.mutelist_manager = mutelist_manager self.profiles = profiles self.dms = dms self.previews = previews @@ -107,6 +109,7 @@ struct DamusState: HeadlessDamusState { likes: EventCounter(our_pubkey: empty_pub), boosts: EventCounter(our_pubkey: empty_pub), contacts: Contacts(our_pubkey: empty_pub), + mutelist_manager: MutelistManager(), profiles: Profiles(ndb: .empty), dms: DirectMessagesModel(our_pubkey: empty_pub), previews: PreviewCache(), diff --git a/damus/Models/HeadlessDamusState.swift b/damus/Models/HeadlessDamusState.swift index dcb9d032..d888c09d 100644 --- a/damus/Models/HeadlessDamusState.swift +++ b/damus/Models/HeadlessDamusState.swift @@ -15,6 +15,7 @@ protocol HeadlessDamusState { var ndb: Ndb { get } var settings: UserSettingsStore { get } var contacts: Contacts { get } + var mutelist_manager: MutelistManager { get } var keypair: Keypair { get } var profiles: Profiles { get } var zaps: Zaps { get } diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift index 9ea9833d..25f894bd 100644 --- a/damus/Models/HomeModel.swift +++ b/damus/Models/HomeModel.swift @@ -244,7 +244,7 @@ class HomeModel { process_zap_event(state: damus_state, ev: ev) { zapres in guard case .done(let zap) = zapres, zap.target.pubkey == self.damus_state.keypair.pubkey, - should_show_event(contacts: self.damus_state.contacts, ev: zap.request.ev) else { + should_show_event(state: self.damus_state, ev: zap.request.ev) else { return } @@ -278,11 +278,11 @@ class HomeModel { func filter_events() { events.filter { ev in - !damus_state.contacts.is_muted(.user(ev.pubkey, nil)) + !damus_state.mutelist_manager.is_muted(.user(ev.pubkey, nil)) } self.dms.dms = dms.dms.filter { ev in - !damus_state.contacts.is_muted(.user(ev.pubkey, nil)) + !damus_state.mutelist_manager.is_muted(.user(ev.pubkey, nil)) } notifications.filter { ev in @@ -290,7 +290,7 @@ class HomeModel { return false } - let event_muted = damus_state.contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil + let event_muted = damus_state.mutelist_manager.is_event_muted(ev) return !event_muted } } @@ -570,13 +570,13 @@ class HomeModel { } // we only care about the most recent mutelist - if let mutelist = damus_state.contacts.mutelist { + if let mutelist = damus_state.mutelist_manager.event { if ev.created_at <= mutelist.created_at { return } } - damus_state.contacts.set_mutelist(ev) + damus_state.mutelist_manager.set_mutelist(ev) migrate_old_muted_threads_to_new_mutelist(keypair: damus_state.keypair, damus_state: damus_state) } @@ -588,7 +588,7 @@ class HomeModel { } // we only care about the most recent mutelist - if let mutelist = damus_state.contacts.mutelist { + if let mutelist = damus_state.mutelist_manager.event { if ev.created_at <= mutelist.created_at { return } @@ -598,7 +598,7 @@ class HomeModel { return } - damus_state.contacts.set_mutelist(ev) + damus_state.mutelist_manager.set_mutelist(ev) migrate_old_muted_threads_to_new_mutelist(keypair: damus_state.keypair, damus_state: damus_state) } @@ -616,7 +616,7 @@ class HomeModel { // don't show notifications from ourselves guard ev.pubkey != damus_state.pubkey, event_has_our_pubkey(ev, our_pubkey: self.damus_state.pubkey), - should_show_event(contacts: damus_state.contacts, ev: ev) else { + should_show_event(state: damus_state, ev: ev) else { return } @@ -654,7 +654,7 @@ class HomeModel { func handle_text_event(sub_id: String, _ ev: NostrEvent) { - guard should_show_event(contacts: damus_state.contacts, ev: ev) else { + guard should_show_event(state: damus_state, ev: ev) else { return } @@ -683,7 +683,7 @@ class HomeModel { } func handle_dm(_ ev: NostrEvent) { - guard should_show_event(contacts: damus_state.contacts, ev: ev) else { + guard should_show_event(state: damus_state, ev: ev) else { return } @@ -1090,13 +1090,13 @@ func event_has_our_pubkey(_ ev: NostrEvent, our_pubkey: Pubkey) -> Bool { func should_show_event(event: NostrEvent, damus_state: DamusState) -> Bool { return should_show_event( - contacts: damus_state.contacts, + state: damus_state, ev: event ) } -func should_show_event(contacts: Contacts, ev: NostrEvent) -> Bool { - let event_muted = contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil +func should_show_event(state: DamusState, ev: NostrEvent, keypair: Keypair? = nil) -> Bool { + let event_muted = state.mutelist_manager.is_event_muted(ev, keypair: keypair) if event_muted { return false } diff --git a/damus/Models/MuteItem.swift b/damus/Models/MuteItem.swift index 69bbe2c0..8df15a1d 100644 --- a/damus/Models/MuteItem.swift +++ b/damus/Models/MuteItem.swift @@ -200,64 +200,3 @@ extension MuteItem: TagConvertible { } } -extension Collection where Element == MuteItem { - /// Check if an event is muted given a collection of ``MutedItem``. - /// - /// - Parameter ev: The ``NostrEvent`` that you want to check the muted reason for. - /// - Returns: The ``MuteItem`` that matched the event. Or `nil` if the event is not muted. - func event_muted_reason(_ ev: NostrEvent) -> MuteItem? { - return self.first { muted_item in - switch muted_item { - case .user(let pubkey, let expiration_date): - return pubkey == ev.pubkey && !muted_item.is_expired() - case .hashtag(let hashtag, let expiration_date): - return ev.referenced_hashtags.contains(hashtag) && !muted_item.is_expired() - case .word(let word, let expiration_date): - return ev.content.lowercased().contains(word.lowercased()) && !muted_item.is_expired() - case .thread(let note_id, let expiration_date): - return ev.referenced_ids.contains(note_id) && !muted_item.is_expired() - } - } - } - - var users: [Pubkey] { - return self.compactMap { muted_item in - if case .user(let pubkey, _) = muted_item, - !muted_item.is_expired() { - return pubkey - } else { - return nil - } - } - } - var hashtags: [Hashtag] { - return self.compactMap { muted_item in - if case .hashtag(let hashtag, _) = muted_item, - !muted_item.is_expired() { - return hashtag - } else { - return nil - } - } - } - var words: [String] { - return self.compactMap { muted_item in - if case .word(let str, _) = muted_item, - !muted_item.is_expired() { - return str - } else { - return nil - } - } - } - var threads: [NoteId] { - return self.compactMap { muted_item in - if case .thread(let note_id, _) = muted_item, - !muted_item.is_expired() { - return note_id - } else { - return nil - } - } - } -} diff --git a/damus/Models/MutedThreadsManager.swift b/damus/Models/MutedThreadsManager.swift index 20c1903f..7a4e2c25 100644 --- a/damus/Models/MutedThreadsManager.swift +++ b/damus/Models/MutedThreadsManager.swift @@ -30,9 +30,9 @@ func migrate_old_muted_threads_to_new_mutelist(keypair: Keypair, damus_state: Da let mutedThreads = loadOldMutedThreads(pubkey: fullKeypair.pubkey) guard !mutedThreads.isEmpty else { return } // Set new muted system for those existing threads - let previous_mute_list_event = damus_state.contacts.mutelist + let previous_mute_list_event = damus_state.mutelist_manager.event guard let new_mutelist_event = create_or_update_mutelist(keypair: fullKeypair, mprev: previous_mute_list_event, to_add: Set(mutedThreads.map { MuteItem.thread($0, nil) })) else { return } - damus_state.contacts.set_mutelist(new_mutelist_event) + damus_state.mutelist_manager.set_mutelist(new_mutelist_event) damus_state.postbox.send(new_mutelist_event) // Set existing muted threads to an empty array UserDefaults.standard.set([], forKey: getMutedThreadsKey(pubkey: keypair.pubkey)) diff --git a/damus/Models/NotificationsManager.swift b/damus/Models/NotificationsManager.swift index 5718f56c..d0a9f313 100644 --- a/damus/Models/NotificationsManager.swift +++ b/damus/Models/NotificationsManager.swift @@ -37,7 +37,7 @@ func should_display_notification(state: HeadlessDamusState, event ev: NostrEvent } // Don't show notifications that match mute list. - if state.contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil { + if state.mutelist_manager.is_event_muted(ev, keypair: state.keypair) { return false } diff --git a/damus/Models/SearchHomeModel.swift b/damus/Models/SearchHomeModel.swift index 63bcc810..33f4b608 100644 --- a/damus/Models/SearchHomeModel.swift +++ b/damus/Models/SearchHomeModel.swift @@ -35,7 +35,7 @@ class SearchHomeModel: ObservableObject { } func filter_muted() { - events.filter { should_show_event(contacts: damus_state.contacts, ev: $0) } + events.filter { should_show_event(state: damus_state, ev: $0) } self.objectWillChange.send() } @@ -60,7 +60,7 @@ class SearchHomeModel: ObservableObject { guard sub_id == self.base_subid || sub_id == self.profiles_subid else { return } - if ev.is_textlike && should_show_event(contacts: damus_state.contacts, ev: ev) && !ev.is_reply(damus_state.keypair) + if ev.is_textlike && should_show_event(state: damus_state, ev: ev) && !ev.is_reply(damus_state.keypair) { if !damus_state.settings.multiple_events_per_pubkey && seen_pubkey.contains(ev.pubkey) { return diff --git a/damus/Models/SearchModel.swift b/damus/Models/SearchModel.swift index 1d107fc3..faebe284 100644 --- a/damus/Models/SearchModel.swift +++ b/damus/Models/SearchModel.swift @@ -28,7 +28,7 @@ class SearchModel: ObservableObject { func filter_muted() { self.events.filter { - should_show_event(contacts: state.contacts, ev: $0) + should_show_event(state: state, ev: $0) } self.objectWillChange.send() } @@ -57,7 +57,7 @@ class SearchModel: ObservableObject { return } - guard should_show_event(contacts: state.contacts, ev: ev) else { + guard should_show_event(state: state, ev: ev) else { return } diff --git a/damus/TestData.swift b/damus/TestData.swift index f9515bb5..127468a7 100644 --- a/damus/TestData.swift +++ b/damus/TestData.swift @@ -73,6 +73,7 @@ var test_damus_state: DamusState = ({ likes: .init(our_pubkey: our_pubkey), boosts: .init(our_pubkey: our_pubkey), contacts: .init(our_pubkey: our_pubkey), + mutelist_manager: MutelistManager(), profiles: .init(ndb: ndb), dms: .init(our_pubkey: our_pubkey), previews: .init(), diff --git a/damus/Util/Router.swift b/damus/Util/Router.swift index fbcaf801..6ac44882 100644 --- a/damus/Util/Router.swift +++ b/damus/Util/Router.swift @@ -14,7 +14,7 @@ enum Route: Hashable { case Relay(relay: String, showActionButtons: Binding) case RelayDetail(relay: String, metadata: RelayMetadata?) case Following(following: FollowingModel) - case MuteList(mutelist_items: Set) + case MuteList case RelayConfig case Script(script: ScriptModel) case Bookmarks @@ -58,8 +58,8 @@ enum Route: Hashable { RelayDetailView(state: damusState, relay: relay, nip11: metadata) case .Following(let following): FollowingView(damus_state: damusState, following: following) - case .MuteList(let mutelist_items): - MutelistView(damus_state: damusState, mutelist_items: mutelist_items) + case .MuteList: + MutelistView(damus_state: damusState) case .RelayConfig: RelayConfigView(state: damusState) case .Bookmarks: @@ -139,9 +139,8 @@ enum Route: Hashable { hasher.combine(relay) case .Following: hasher.combine("following") - case .MuteList(let users): + case .MuteList: hasher.combine("muteList") - hasher.combine(users) case .RelayConfig: hasher.combine("relayConfig") case .Bookmarks: diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift index a6222aa8..32a39fbc 100644 --- a/damus/Views/DMChatView.swift +++ b/damus/Views/DMChatView.swift @@ -20,7 +20,7 @@ struct DMChatView: View, KeyboardReadable { ScrollViewReader { scroller in ScrollView { LazyVStack(alignment: .leading) { - ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in + ForEach(Array(zip(dms.events, dms.events.indices)).filter { should_show_event(state: damus_state, ev: $0.0, keypair: damus_state.keypair)}, id: \.0.id) { (ev, ind) in DMView(event: dms.events[ind], damus_state: damus_state) .contextMenu{MenuItems(damus_state: damus_state, event: ev, target_pubkey: ev.pubkey, profileModel: ProfileModel(pubkey: ev.pubkey, damus: damus_state))} } diff --git a/damus/Views/DirectMessagesView.swift b/damus/Views/DirectMessagesView.swift index 6d3cfacc..a0874a98 100644 --- a/damus/Views/DirectMessagesView.swift +++ b/damus/Views/DirectMessagesView.swift @@ -39,7 +39,7 @@ struct DirectMessagesView: View { func filter_dms(dms: [DirectMessageModel]) -> [DirectMessageModel] { return dms.filter({ dm in - return damus_state.settings.friend_filter.filter(contacts: damus_state.contacts, pubkey: dm.pubkey) && !damus_state.contacts.is_muted(.user(dm.pubkey, nil)) + return damus_state.settings.friend_filter.filter(contacts: damus_state.contacts, pubkey: dm.pubkey) && !damus_state.mutelist_manager.is_muted(.user(dm.pubkey, nil)) }) } @@ -53,7 +53,7 @@ struct DirectMessagesView: View { func MaybeEvent(_ model: DirectMessageModel) -> some View { Group { - if let ev = model.events.last { + if let ev = model.events.last(where: { should_show_event(state: damus_state, ev: $0, keypair: damus_state.keypair) }) { EventView(damus: damus_state, event: ev, pubkey: model.pubkey, options: options) .onTapGesture { self.model.set_active_dm_model(model) diff --git a/damus/Views/Events/EventMenu.swift b/damus/Views/Events/EventMenu.swift index d3144b1d..af267989 100644 --- a/damus/Views/Events/EventMenu.swift +++ b/damus/Views/Events/EventMenu.swift @@ -55,7 +55,7 @@ struct MenuItems: View { let bookmarked = damus_state.bookmarks.isBookmarked(event) self._isBookmarked = State(initialValue: bookmarked) - let muted_thread = (damus_state.contacts.mutelist?.mute_list?.event_muted_reason(event) != nil) + let muted_thread = damus_state.mutelist_manager.is_event_muted(event) self._isMutedThread = State(initialValue: muted_thread) self.damus_state = damus_state @@ -111,11 +111,11 @@ struct MenuItems: View { if event.known_kind != .dm { MuteDurationMenu { duration in if let full_keypair = self.damus_state.keypair.to_full(), - let new_mutelist_ev = toggle_from_mutelist(keypair: full_keypair, prev: damus_state.contacts.mutelist, to_toggle: .thread(event.thread_id(keypair: damus_state.keypair), duration?.date_from_now)) { - damus_state.contacts.set_mutelist(new_mutelist_ev) + let new_mutelist_ev = toggle_from_mutelist(keypair: full_keypair, prev: damus_state.mutelist_manager.event, to_toggle: .thread(event.thread_id(keypair: damus_state.keypair), duration?.date_from_now)) { + damus_state.mutelist_manager.set_mutelist(new_mutelist_ev) damus_state.postbox.send(new_mutelist_ev) } - let muted = (damus_state.contacts.mutelist?.mute_list?.event_muted_reason(event) != nil) + let muted = damus_state.mutelist_manager.is_event_muted(event) isMutedThread = muted } label: { let imageName = isMutedThread ? "mute" : "mute" diff --git a/damus/Views/Events/EventMutingContainerView.swift b/damus/Views/Events/EventMutingContainerView.swift index c030be24..44887ac8 100644 --- a/damus/Views/Events/EventMutingContainerView.swift +++ b/damus/Views/Events/EventMutingContainerView.swift @@ -27,7 +27,7 @@ struct EventMutingContainerView: View { self.damus_state = damus_state self.event = event self.content = content() - self._shown = State(initialValue: should_show_event(contacts: damus_state.contacts, ev: event)) + self._shown = State(initialValue: should_show_event(state: damus_state, ev: event)) } init(damus_state: DamusState, event: NostrEvent, muteBox: @escaping MuteBoxViewClosure, @ViewBuilder content: () -> Content) { @@ -36,7 +36,7 @@ struct EventMutingContainerView: View { } var should_mute: Bool { - return !should_show_event(contacts: damus_state.contacts, ev: event) + return !should_show_event(state: damus_state, ev: event) } var body: some View { @@ -54,14 +54,14 @@ struct EventMutingContainerView: View { } } .onReceive(handle_notify(.new_mutes)) { mutes in - let new_muted_event_reason = mutes.event_muted_reason(event) + let new_muted_event_reason = damus_state.mutelist_manager.event_muted_reason(event) if new_muted_event_reason != nil { shown = false muted_reason = new_muted_event_reason } } .onReceive(handle_notify(.new_unmutes)) { unmutes in - if unmutes.event_muted_reason(event) != nil { + if damus_state.mutelist_manager.event_muted_reason(event) != nil { shown = true muted_reason = nil } diff --git a/damus/Views/Muting/AddMuteItemView.swift b/damus/Views/Muting/AddMuteItemView.swift index 46699735..cbc4f974 100644 --- a/damus/Views/Muting/AddMuteItemView.swift +++ b/damus/Views/Muting/AddMuteItemView.swift @@ -72,7 +72,7 @@ struct AddMuteItemView: View { // Actually update & relay the new mute list if let mute_item { - let existing_mutelist = state.contacts.mutelist + let existing_mutelist = state.mutelist_manager.event guard let full_keypair = state.keypair.to_full(), @@ -81,7 +81,7 @@ struct AddMuteItemView: View { return } - state.contacts.set_mutelist(mutelist) + state.mutelist_manager.set_mutelist(mutelist) state.postbox.send(mutelist) } diff --git a/damus/Views/Muting/MutelistView.swift b/damus/Views/Muting/MutelistView.swift index 37813383..2091c929 100644 --- a/damus/Views/Muting/MutelistView.swift +++ b/damus/Views/Muting/MutelistView.swift @@ -9,12 +9,16 @@ import SwiftUI struct MutelistView: View { let damus_state: DamusState - @State var mutelist_items: Set = Set() @State var show_add_muteitem: Bool = false + @State var users: [MuteItem] = [] + @State var hashtags: [MuteItem] = [] + @State var threads: [MuteItem] = [] + @State var words: [MuteItem] = [] + func RemoveAction(item: MuteItem) -> some View { Button { - guard let mutelist = damus_state.contacts.mutelist, + guard let mutelist = damus_state.mutelist_manager.event, let keypair = damus_state.keypair.to_full(), let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, @@ -23,74 +27,88 @@ struct MutelistView: View { return } - damus_state.contacts.set_mutelist(new_ev) + damus_state.mutelist_manager.set_mutelist(new_ev) damus_state.postbox.send(new_ev) - mutelist_items = new_ev.mute_list ?? Set() + updateMuteItems() } label: { Label(NSLocalizedString("Delete", comment: "Button to remove a user from their mutelist."), image: "delete") } .tint(.red) } + func updateMuteItems() { + users = Array(damus_state.mutelist_manager.users) + hashtags = Array(damus_state.mutelist_manager.hashtags) + threads = Array(damus_state.mutelist_manager.threads) + words = Array(damus_state.mutelist_manager.words) + } var body: some View { List { Section(NSLocalizedString("Users", comment: "Section header title for a list of muted users.")) { - ForEach(mutelist_items.users, id: \.self) { pubkey in - UserViewRow(damus_state: damus_state, pubkey: pubkey) - .id(pubkey) - .swipeActions { - RemoveAction(item: .user(pubkey, nil)) - } - .onTapGesture { - damus_state.nav.push(route: Route.ProfileByKey(pubkey: pubkey)) - } + ForEach(users, id: \.self) { user in + if case let MuteItem.user(pubkey, _) = user { + UserViewRow(damus_state: damus_state, pubkey: pubkey) + .id(pubkey) + .swipeActions { + RemoveAction(item: .user(pubkey, nil)) + } + .onTapGesture { + damus_state.nav.push(route: Route.ProfileByKey(pubkey: pubkey)) + } + } } } Section(NSLocalizedString("Hashtags", comment: "Section header title for a list of hashtags that are muted.")) { - ForEach(mutelist_items.hashtags, id: \.hashtag) { hashtag in - Text("#\(hashtag.hashtag)") - .id(hashtag.hashtag) - .swipeActions { - RemoveAction(item: .hashtag(hashtag, nil)) - } - .onTapGesture { - damus_state.nav.push(route: Route.Search(search: SearchModel.init(state: damus_state, search: NostrFilter(hashtag: [hashtag.hashtag])))) - } + ForEach(hashtags, id: \.self) { item in + if case let MuteItem.hashtag(hashtag, _) = item { + Text("#\(hashtag.hashtag)") + .id(hashtag.hashtag) + .swipeActions { + RemoveAction(item: .hashtag(hashtag, nil)) + } + .onTapGesture { + damus_state.nav.push(route: Route.Search(search: SearchModel.init(state: damus_state, search: NostrFilter(hashtag: [hashtag.hashtag])))) + } + } } } Section(NSLocalizedString("Words", comment: "Section header title for a list of words that are muted.")) { - ForEach(mutelist_items.words, id: \.self) { word in - Text("\(word)") - .id(word) - .swipeActions { - RemoveAction(item: .word(word, nil)) - } + ForEach(words, id: \.self) { item in + if case let MuteItem.word(word, _) = item { + Text("\(word)") + .id(word) + .swipeActions { + RemoveAction(item: .word(word, nil)) + } + } } } Section(NSLocalizedString("Threads", comment: "Section header title for a list of threads that are muted.")) { - ForEach(mutelist_items.threads, id: \.self) { note_id in - if let event = damus_state.events.lookup(note_id) { - EventView(damus: damus_state, event: event) - .id(note_id.hex()) - .swipeActions { - RemoveAction(item: .thread(note_id, nil)) - } - } else { - Text(NSLocalizedString("Error retrieving muted event", comment: "Text for an item that application failed to retrieve the muted event for.")) + ForEach(threads, id: \.self) { item in + if case let MuteItem.thread(note_id, _) = item { + if let event = damus_state.events.lookup(note_id) { + EventView(damus: damus_state, event: event) + .id(note_id.hex()) + .swipeActions { + RemoveAction(item: .thread(note_id, nil)) + } + } else { + Text(NSLocalizedString("Error retrieving muted event", comment: "Text for an item that application failed to retrieve the muted event for.")) + } } } } } .navigationTitle(NSLocalizedString("Muted", comment: "Navigation title of view to see list of muted users & phrases.")) .onAppear { - mutelist_items = damus_state.contacts.mutelist?.mute_list ?? Set() + updateMuteItems() } .onReceive(handle_notify(.new_mutes)) { new_mutes in - mutelist_items = mutelist_items.union(new_mutes) + updateMuteItems() } .onReceive(handle_notify(.new_unmutes)) { new_unmutes in - mutelist_items = mutelist_items.subtracting(new_unmutes) + updateMuteItems() } .toolbar { ToolbarItem(placement: .topBarTrailing) { @@ -115,11 +133,6 @@ struct MutelistView: View { struct MutelistView_Previews: PreviewProvider { static var previews: some View { - MutelistView(damus_state: test_damus_state, mutelist_items: Set([ - .user(test_note.pubkey, nil), - .hashtag(Hashtag(hashtag: "test"), nil), - .word("test", nil), - .thread(test_note.id, nil) - ])) + MutelistView(damus_state: test_damus_state) } } diff --git a/damus/Views/Profile/ProfileView.swift b/damus/Views/Profile/ProfileView.swift index e8f3e2f9..c3ff327a 100644 --- a/damus/Views/Profile/ProfileView.swift +++ b/damus/Views/Profile/ProfileView.swift @@ -179,11 +179,11 @@ struct ProfileView: View { notify(.report(.user(profile.pubkey))) } - if damus_state.contacts.is_muted(.user(profile.pubkey, nil)) { + if damus_state.mutelist_manager.is_muted(.user(profile.pubkey, nil)) { Button(NSLocalizedString("Unmute", comment: "Button to unmute a profile.")) { guard let keypair = damus_state.keypair.to_full(), - let mutelist = damus_state.contacts.mutelist + let mutelist = damus_state.mutelist_manager.event else { return } @@ -192,7 +192,7 @@ struct ProfileView: View { return } - damus_state.contacts.set_mutelist(new_ev) + damus_state.mutelist_manager.set_mutelist(new_ev) damus_state.postbox.send(new_ev) } } else { diff --git a/damus/Views/SearchHomeView.swift b/damus/Views/SearchHomeView.swift index 91a15e2d..3aa13c8d 100644 --- a/damus/Views/SearchHomeView.swift +++ b/damus/Views/SearchHomeView.swift @@ -59,7 +59,7 @@ struct SearchHomeView: View { return false } - let event_muted = damus_state.contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil + let event_muted = damus_state.mutelist_manager.is_event_muted(ev) if event_muted { return false } diff --git a/damus/Views/SearchView.swift b/damus/Views/SearchView.swift index 3d5fddf5..083225ab 100644 --- a/damus/Views/SearchView.swift +++ b/damus/Views/SearchView.swift @@ -62,13 +62,13 @@ struct SearchView: View { Button { guard let full_keypair = appstate.keypair.to_full(), - let existing_mutelist = appstate.contacts.mutelist, + let existing_mutelist = appstate.mutelist_manager.event, let mutelist = remove_from_mutelist(keypair: full_keypair, prev: existing_mutelist, to_remove: .hashtag(Hashtag(hashtag: hashtag), nil)) else { return } - appstate.contacts.set_mutelist(mutelist) + appstate.mutelist_manager.set_mutelist(mutelist) appstate.postbox.send(mutelist) } label: { Text("Unmute Hashtag", comment: "Label represnting a button that the user can tap to unmute a given hashtag so they start seeing it in their feed again.") @@ -88,7 +88,7 @@ struct SearchView: View { } .onAppear { if let hashtag_string = search.search.hashtag?.first { - is_hashtag_muted = (appstate.contacts.mutelist?.mute_list ?? []).contains(MuteItem.hashtag(Hashtag(hashtag: hashtag_string), nil)) + is_hashtag_muted = (appstate.mutelist_manager.event?.mute_list ?? []).contains(MuteItem.hashtag(Hashtag(hashtag: hashtag_string), nil)) } } } @@ -96,13 +96,13 @@ struct SearchView: View { func mute_hashtag(hashtag_string: String, expiration_time: Date?) { guard let full_keypair = appstate.keypair.to_full(), - let existing_mutelist = appstate.contacts.mutelist, + let existing_mutelist = appstate.mutelist_manager.event, let mutelist = create_or_update_mutelist(keypair: full_keypair, mprev: existing_mutelist, to_add: .hashtag(Hashtag(hashtag: hashtag_string), expiration_time)) else { return } - appstate.contacts.set_mutelist(mutelist) + appstate.mutelist_manager.set_mutelist(mutelist) appstate.postbox.send(mutelist) } diff --git a/damus/Views/SideMenuView.swift b/damus/Views/SideMenuView.swift index fe3b6eca..abe5adbe 100644 --- a/damus/Views/SideMenuView.swift +++ b/damus/Views/SideMenuView.swift @@ -66,7 +66,7 @@ struct SideMenuView: View { } } - NavigationLink(value: Route.MuteList(mutelist_items: damus_state.contacts.mutelist?.mute_list ?? Set())) { + NavigationLink(value: Route.MuteList) { navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute") }