Compare commits
1 Commits
hide-hellt
...
tyiu/mute-
| Author | SHA1 | Date | |
|---|---|---|---|
|
84183d2b83
|
@@ -17,6 +17,7 @@
|
|||||||
3A3040F329A91366008A0F29 /* ProfileViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F229A91366008A0F29 /* ProfileViewTests.swift */; };
|
3A3040F329A91366008A0F29 /* ProfileViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F229A91366008A0F29 /* ProfileViewTests.swift */; };
|
||||||
3A30410129AB12AA008A0F29 /* EventGroupViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30410029AB12AA008A0F29 /* EventGroupViewTests.swift */; };
|
3A30410129AB12AA008A0F29 /* EventGroupViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30410029AB12AA008A0F29 /* EventGroupViewTests.swift */; };
|
||||||
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
|
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
|
||||||
|
3A48E7B029DFBE9D006E787E /* MutedThreadsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A48E7AF29DFBE9D006E787E /* MutedThreadsManager.swift */; };
|
||||||
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
|
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
|
||||||
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
|
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
|
||||||
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
|
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
|
||||||
@@ -328,6 +329,7 @@
|
|||||||
3A41E559299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
3A41E559299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
3A41E55A299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
|
3A41E55A299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
3A41E55B299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = id; path = id.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
3A41E55B299D52BE001FA465 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = id; path = id.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
|
3A48E7AF29DFBE9D006E787E /* MutedThreadsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutedThreadsManager.swift; sourceTree = "<group>"; };
|
||||||
3A4F3320297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
3A4F3320297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
3A4F3321297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
3A4F3321297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
3A4F3322297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "fr-FR"; path = "fr-FR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
3A4F3322297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "fr-FR"; path = "fr-FR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||||
@@ -840,6 +842,7 @@
|
|||||||
3AA59D1C2999B0400061C48E /* DraftsModel.swift */,
|
3AA59D1C2999B0400061C48E /* DraftsModel.swift */,
|
||||||
4C54AA0629A540BA003E4487 /* NotificationsModel.swift */,
|
4C54AA0629A540BA003E4487 /* NotificationsModel.swift */,
|
||||||
4CD348EE29C3659D00497EB2 /* ImageUploadModel.swift */,
|
4CD348EE29C3659D00497EB2 /* ImageUploadModel.swift */,
|
||||||
|
3A48E7AF29DFBE9D006E787E /* MutedThreadsManager.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1535,6 +1538,7 @@
|
|||||||
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
|
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
|
||||||
4CB883A62975F83C00DC99E7 /* LNUrlPayRequest.swift in Sources */,
|
4CB883A62975F83C00DC99E7 /* LNUrlPayRequest.swift in Sources */,
|
||||||
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */,
|
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */,
|
||||||
|
3A48E7B029DFBE9D006E787E /* MutedThreadsManager.swift in Sources */,
|
||||||
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,
|
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,
|
||||||
F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */,
|
F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */,
|
||||||
4C8D00CA29DF80350036AF10 /* TruncatedText.swift in Sources */,
|
4C8D00CA29DF80350036AF10 /* TruncatedText.swift in Sources */,
|
||||||
|
|||||||
@@ -471,6 +471,12 @@ struct ContentView: View {
|
|||||||
.onReceive(handle_notify(.new_mutes)) { notif in
|
.onReceive(handle_notify(.new_mutes)) { notif in
|
||||||
home.filter_muted()
|
home.filter_muted()
|
||||||
}
|
}
|
||||||
|
.onReceive(handle_notify(.mute_thread)) { notif in
|
||||||
|
home.filter_muted()
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.unmute_thread)) { notif in
|
||||||
|
home.filter_muted()
|
||||||
|
}
|
||||||
.alert(NSLocalizedString("Deleted Account", comment: "Alert message to indicate this is a deleted account"), isPresented: $is_deleted_account) {
|
.alert(NSLocalizedString("Deleted Account", comment: "Alert message to indicate this is a deleted account"), isPresented: $is_deleted_account) {
|
||||||
Button(NSLocalizedString("Logout", comment: "Button to close the alert that informs that the current account has been deleted.")) {
|
Button(NSLocalizedString("Logout", comment: "Button to close the alert that informs that the current account has been deleted.")) {
|
||||||
is_deleted_account = false
|
is_deleted_account = false
|
||||||
@@ -633,7 +639,8 @@ struct ContentView: View {
|
|||||||
bookmarks: BookmarksManager(pubkey: pubkey),
|
bookmarks: BookmarksManager(pubkey: pubkey),
|
||||||
postbox: PostBox(pool: pool),
|
postbox: PostBox(pool: pool),
|
||||||
bootstrap_relays: bootstrap_relays,
|
bootstrap_relays: bootstrap_relays,
|
||||||
replies: ReplyCounter(our_pubkey: pubkey)
|
replies: ReplyCounter(our_pubkey: pubkey),
|
||||||
|
muted_threads: MutedThreadsManager(pubkey: pubkey)
|
||||||
)
|
)
|
||||||
home.damus_state = self.damus_state!
|
home.damus_state = self.damus_state!
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ struct DamusState {
|
|||||||
let postbox: PostBox
|
let postbox: PostBox
|
||||||
let bootstrap_relays: [String]
|
let bootstrap_relays: [String]
|
||||||
let replies: ReplyCounter
|
let replies: ReplyCounter
|
||||||
|
let muted_threads: MutedThreadsManager
|
||||||
|
|
||||||
var pubkey: String {
|
var pubkey: String {
|
||||||
return keypair.pubkey
|
return keypair.pubkey
|
||||||
@@ -39,6 +40,6 @@ struct DamusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var empty: DamusState {
|
static var empty: DamusState {
|
||||||
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts(), events: EventCache(), bookmarks: BookmarksManager(pubkey: ""), postbox: PostBox(pool: RelayPool()), bootstrap_relays: [], replies: ReplyCounter(our_pubkey: ""))
|
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore(), relay_filters: RelayFilters(our_pubkey: ""), relay_metadata: RelayMetadatas(), drafts: Drafts(), events: EventCache(), bookmarks: BookmarksManager(pubkey: ""), postbox: PostBox(pool: RelayPool()), bootstrap_relays: [], replies: ReplyCounter(our_pubkey: ""), muted_threads: MutedThreadsManager(pubkey: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,12 +52,14 @@ class HomeModel: ObservableObject {
|
|||||||
init() {
|
init() {
|
||||||
self.damus_state = DamusState.empty
|
self.damus_state = DamusState.empty
|
||||||
self.dms = DirectMessagesModel(our_pubkey: "")
|
self.dms = DirectMessagesModel(our_pubkey: "")
|
||||||
|
filter_muted()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(damus_state: DamusState) {
|
init(damus_state: DamusState) {
|
||||||
self.damus_state = damus_state
|
self.damus_state = damus_state
|
||||||
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
|
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
|
||||||
self.setup_debouncer()
|
self.setup_debouncer()
|
||||||
|
filter_muted()
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool: RelayPool {
|
var pool: RelayPool {
|
||||||
@@ -134,7 +136,7 @@ class HomeModel: ObservableObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !notifications.insert_zap(zap) {
|
if !notifications.insert_zap(zap, damus_state: damus_state) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,9 +199,9 @@ class HomeModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func filter_muted() {
|
func filter_muted() {
|
||||||
events.filter { !damus_state.contacts.is_muted($0.pubkey) }
|
events.filter { !damus_state.contacts.is_muted($0.pubkey) && !damus_state.muted_threads.isMutedThread($0) }
|
||||||
self.dms.dms = dms.dms.filter { !damus_state.contacts.is_muted($0.0) }
|
self.dms.dms = dms.dms.filter { !damus_state.contacts.is_muted($0.0) }
|
||||||
notifications.filter { !damus_state.contacts.is_muted($0.pubkey) }
|
notifications.filter_and_build_notifications(damus_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_delete_event(_ ev: NostrEvent) {
|
func handle_delete_event(_ ev: NostrEvent) {
|
||||||
@@ -478,7 +480,7 @@ class HomeModel: ObservableObject {
|
|||||||
damus_state.events.insert(inner_ev)
|
damus_state.events.insert(inner_ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !notifications.insert_event(ev) {
|
if !notifications.insert_event(ev, damus_state: damus_state) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,6 +1041,11 @@ func process_local_notification(damus_state: DamusState, event ev: NostrEvent) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't show notifications from muted threads.
|
||||||
|
if damus_state.muted_threads.isMutedThread(ev) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if type == .text && damus_state.settings.mention_notification {
|
if type == .text && damus_state.settings.mention_notification {
|
||||||
for block in ev.blocks(damus_state.keypair.privkey) {
|
for block in ev.blocks(damus_state.keypair.privkey) {
|
||||||
if case .mention(let mention) = block, mention.ref.ref_id == damus_state.keypair.pubkey,
|
if case .mention(let mention) = block, mention.ref.ref_id == damus_state.keypair.pubkey,
|
||||||
|
|||||||
76
damus/Models/MutedThreadsManager.swift
Normal file
76
damus/Models/MutedThreadsManager.swift
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// MutedThreadsManager.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Terry Yiu on 4/6/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
fileprivate func getMutedThreadsKey(pubkey: String) -> String {
|
||||||
|
pk_setting_key(pubkey, key: "muted_threads")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadMutedThreads(pubkey: String) -> [String] {
|
||||||
|
let key = getMutedThreadsKey(pubkey: pubkey)
|
||||||
|
return UserDefaults.standard.stringArray(forKey: key) ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveMutedThreads(pubkey: String, currentValue: [String], value: [String]) -> Bool {
|
||||||
|
let uniqueMutedThreads = Array(Set(value))
|
||||||
|
|
||||||
|
if uniqueMutedThreads != currentValue {
|
||||||
|
UserDefaults.standard.set(uniqueMutedThreads, forKey: getMutedThreadsKey(pubkey: pubkey))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
class MutedThreadsManager: ObservableObject {
|
||||||
|
|
||||||
|
private let userDefaults = UserDefaults.standard
|
||||||
|
private let pubkey: String
|
||||||
|
|
||||||
|
private var _mutedThreadsSet: Set<String>
|
||||||
|
private var _mutedThreads: [String]
|
||||||
|
var mutedThreads: [String] {
|
||||||
|
get {
|
||||||
|
return _mutedThreads
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if saveMutedThreads(pubkey: pubkey, currentValue: _mutedThreads, value: newValue) {
|
||||||
|
self._mutedThreads = newValue
|
||||||
|
self.objectWillChange.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(pubkey: String) {
|
||||||
|
self._mutedThreads = loadMutedThreads(pubkey: pubkey)
|
||||||
|
self._mutedThreadsSet = Set(_mutedThreads)
|
||||||
|
self.pubkey = pubkey
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMutedThread(_ ev: NostrEvent) -> Bool {
|
||||||
|
return _mutedThreadsSet.contains(ev.thread_id(privkey: nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMutedThread(_ ev: NostrEvent) {
|
||||||
|
let threadId = ev.thread_id(privkey: nil)
|
||||||
|
if isMutedThread(ev) {
|
||||||
|
mutedThreads = mutedThreads.filter { $0 != threadId }
|
||||||
|
_mutedThreadsSet.remove(threadId)
|
||||||
|
notify(.unmute_thread, ev)
|
||||||
|
} else {
|
||||||
|
mutedThreads.append(threadId)
|
||||||
|
_mutedThreadsSet.insert(threadId)
|
||||||
|
notify(.mute_thread, ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearAll() {
|
||||||
|
mutedThreads = []
|
||||||
|
_mutedThreadsSet.removeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,7 +129,7 @@ class NotificationsModel: ObservableObject, ScrollQueue {
|
|||||||
for el in zaps {
|
for el in zaps {
|
||||||
let evid = el.key
|
let evid = el.key
|
||||||
let zapgrp = el.value
|
let zapgrp = el.value
|
||||||
|
|
||||||
let notif: NotificationItem = .event_zap(evid, zapgrp)
|
let notif: NotificationItem = .event_zap(evid, zapgrp)
|
||||||
notifs.append(notif)
|
notifs.append(notif)
|
||||||
}
|
}
|
||||||
@@ -233,66 +233,66 @@ class NotificationsModel: ObservableObject, ScrollQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func insert_event(_ ev: NostrEvent) -> Bool {
|
func insert_event(_ ev: NostrEvent, damus_state: DamusState) -> Bool {
|
||||||
if should_queue {
|
if should_queue {
|
||||||
return insert_uniq_sorted_event_created(events: &incoming_events, new_ev: ev)
|
return insert_uniq_sorted_event_created(events: &incoming_events, new_ev: ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if insert_event_immediate(ev) {
|
if insert_event_immediate(ev) {
|
||||||
self.notifications = build_notifications()
|
filter_and_build_notifications(damus_state)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func insert_zap(_ zap: Zap) -> Bool {
|
func insert_zap(_ zap: Zap, damus_state: DamusState) -> Bool {
|
||||||
if should_queue {
|
if should_queue {
|
||||||
return insert_uniq_sorted_zap_by_created(zaps: &incoming_zaps, new_zap: zap)
|
return insert_uniq_sorted_zap_by_created(zaps: &incoming_zaps, new_zap: zap)
|
||||||
}
|
}
|
||||||
|
|
||||||
if insert_zap_immediate(zap) {
|
if insert_zap_immediate(zap) {
|
||||||
self.notifications = build_notifications()
|
filter_and_build_notifications(damus_state)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func filter(_ isIncluded: (NostrEvent) -> Bool) {
|
func filter_and_build_notifications(_ damus_state: DamusState) {
|
||||||
var changed = false
|
var changed = false
|
||||||
var count = 0
|
var count = 0
|
||||||
|
|
||||||
count = incoming_events.count
|
count = incoming_events.count
|
||||||
incoming_events = incoming_events.filter(isIncluded)
|
incoming_events = incoming_events.filter { include_event($0, damus_state: damus_state) }
|
||||||
changed = changed || incoming_events.count != count
|
changed = changed || incoming_events.count != count
|
||||||
|
|
||||||
count = profile_zaps.zaps.count
|
count = profile_zaps.zaps.count
|
||||||
profile_zaps.zaps = profile_zaps.zaps.filter { zap in isIncluded(zap.request.ev) }
|
profile_zaps.zaps = profile_zaps.zaps.filter { zap in include_event(zap.request.ev, damus_state: damus_state) }
|
||||||
changed = changed || profile_zaps.zaps.count != count
|
changed = changed || profile_zaps.zaps.count != count
|
||||||
|
|
||||||
for el in reactions {
|
for el in reactions {
|
||||||
count = el.value.events.count
|
count = el.value.events.count
|
||||||
el.value.events = el.value.events.filter(isIncluded)
|
el.value.events = el.value.events.filter { include_event($0, damus_state: damus_state) }
|
||||||
changed = changed || el.value.events.count != count
|
changed = changed || el.value.events.count != count
|
||||||
}
|
}
|
||||||
|
|
||||||
for el in reposts {
|
for el in reposts {
|
||||||
count = el.value.events.count
|
count = el.value.events.count
|
||||||
el.value.events = el.value.events.filter(isIncluded)
|
el.value.events = el.value.events.filter { include_event($0, damus_state: damus_state) }
|
||||||
changed = changed || el.value.events.count != count
|
changed = changed || el.value.events.count != count
|
||||||
}
|
}
|
||||||
|
|
||||||
for el in zaps {
|
for el in zaps {
|
||||||
count = el.value.zaps.count
|
count = el.value.zaps.count
|
||||||
el.value.zaps = el.value.zaps.filter {
|
el.value.zaps = el.value.zaps.filter {
|
||||||
isIncluded($0.request.ev)
|
include_event($0.request.ev, damus_state: damus_state)
|
||||||
}
|
}
|
||||||
changed = changed || el.value.zaps.count != count
|
changed = changed || el.value.zaps.count != count
|
||||||
}
|
}
|
||||||
|
|
||||||
count = replies.count
|
count = replies.count
|
||||||
replies = replies.filter(isIncluded)
|
replies = replies.filter { include_event($0, damus_state: damus_state) }
|
||||||
changed = changed || replies.count != count
|
changed = changed || replies.count != count
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
@@ -300,7 +300,7 @@ class NotificationsModel: ObservableObject, ScrollQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func flush() -> Bool {
|
func flush(_ damus_state: DamusState) -> Bool {
|
||||||
var inserted = false
|
var inserted = false
|
||||||
|
|
||||||
for zap in incoming_zaps {
|
for zap in incoming_zaps {
|
||||||
@@ -312,9 +312,13 @@ class NotificationsModel: ObservableObject, ScrollQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if inserted {
|
if inserted {
|
||||||
self.notifications = build_notifications()
|
filter_and_build_notifications(damus_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
return inserted
|
return inserted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func include_event(_ event: NostrEvent, damus_state: DamusState) -> Bool {
|
||||||
|
return !damus_state.contacts.is_muted(event.pubkey) && !damus_state.muted_threads.isMutedThread(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,12 @@ extension Notification.Name {
|
|||||||
static var zapping: Notification.Name {
|
static var zapping: Notification.Name {
|
||||||
return Notification.Name("zapping")
|
return Notification.Name("zapping")
|
||||||
}
|
}
|
||||||
|
static var mute_thread: Notification.Name {
|
||||||
|
return Notification.Name("mute_thread")
|
||||||
|
}
|
||||||
|
static var unmute_thread: Notification.Name {
|
||||||
|
return Notification.Name("unmute_thread")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher {
|
func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ struct DMChatView: View {
|
|||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in
|
ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in
|
||||||
DMView(event: dms.events[ind], damus_state: damus_state)
|
DMView(event: dms.events[ind], damus_state: damus_state)
|
||||||
.contextMenu{MenuItems(event: ev, keypair: damus_state.keypair, target_pubkey: ev.pubkey, bookmarks: damus_state.bookmarks)}
|
.contextMenu{MenuItems(event: ev, keypair: damus_state.keypair, target_pubkey: ev.pubkey, bookmarks: damus_state.bookmarks, muted_threads: damus_state.muted_threads)}
|
||||||
}
|
}
|
||||||
EndBlock(height: 80)
|
EndBlock(height: 80)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,9 +93,9 @@ extension View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func event_context_menu(_ event: NostrEvent, keypair: Keypair, target_pubkey: String, bookmarks: BookmarksManager) -> some View {
|
func event_context_menu(_ event: NostrEvent, keypair: Keypair, target_pubkey: String, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager) -> some View {
|
||||||
return self.contextMenu {
|
return self.contextMenu {
|
||||||
EventMenuContext(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks)
|
EventMenuContext(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks, muted_threads: muted_threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct EmbeddedEventView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
EventMenuContext(event: event, keypair: damus_state.keypair, target_pubkey: event.pubkey, bookmarks: damus_state.bookmarks)
|
EventMenuContext(event: event, keypair: damus_state.keypair, target_pubkey: event.pubkey, bookmarks: damus_state.bookmarks, muted_threads: damus_state.muted_threads)
|
||||||
.padding([.bottom], 4)
|
.padding([.bottom], 4)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ struct EventMenuContext: View {
|
|||||||
let keypair: Keypair
|
let keypair: Keypair
|
||||||
let target_pubkey: String
|
let target_pubkey: String
|
||||||
let bookmarks: BookmarksManager
|
let bookmarks: BookmarksManager
|
||||||
|
let muted_threads: MutedThreadsManager
|
||||||
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ struct EventMenuContext: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Menu {
|
Menu {
|
||||||
|
|
||||||
MenuItems(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks)
|
MenuItems(event: event, keypair: keypair, target_pubkey: target_pubkey, bookmarks: bookmarks, muted_threads: muted_threads)
|
||||||
|
|
||||||
} label: {
|
} label: {
|
||||||
Label("", systemImage: "ellipsis")
|
Label("", systemImage: "ellipsis")
|
||||||
@@ -36,14 +37,20 @@ struct MenuItems: View {
|
|||||||
let keypair: Keypair
|
let keypair: Keypair
|
||||||
let target_pubkey: String
|
let target_pubkey: String
|
||||||
let bookmarks: BookmarksManager
|
let bookmarks: BookmarksManager
|
||||||
|
let muted_threads: MutedThreadsManager
|
||||||
|
|
||||||
@State private var isBookmarked: Bool = false
|
@State private var isBookmarked: Bool = false
|
||||||
|
@State private var isMutedThread: Bool = false
|
||||||
|
|
||||||
init(event: NostrEvent, keypair: Keypair, target_pubkey: String, bookmarks: BookmarksManager) {
|
init(event: NostrEvent, keypair: Keypair, target_pubkey: String, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager) {
|
||||||
let bookmarked = bookmarks.isBookmarked(event)
|
let bookmarked = bookmarks.isBookmarked(event)
|
||||||
self._isBookmarked = State(initialValue: bookmarked)
|
self._isBookmarked = State(initialValue: bookmarked)
|
||||||
|
|
||||||
|
let muted_thread = muted_threads.isMutedThread(event)
|
||||||
|
self._isMutedThread = State(initialValue: muted_thread)
|
||||||
|
|
||||||
self.bookmarks = bookmarks
|
self.bookmarks = bookmarks
|
||||||
|
self.muted_threads = muted_threads
|
||||||
self.event = event
|
self.event = event
|
||||||
self.keypair = keypair
|
self.keypair = keypair
|
||||||
self.target_pubkey = target_pubkey
|
self.target_pubkey = target_pubkey
|
||||||
@@ -86,6 +93,19 @@ struct MenuItems: View {
|
|||||||
Label(isBookmarked ? removeBookmarkString : addBookmarkString, systemImage: imageName)
|
Label(isBookmarked ? removeBookmarkString : addBookmarkString, systemImage: imageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.known_kind != .dm {
|
||||||
|
Button {
|
||||||
|
self.muted_threads.updateMutedThread(event)
|
||||||
|
let muted = self.muted_threads.isMutedThread(event)
|
||||||
|
isMutedThread = muted
|
||||||
|
} label: {
|
||||||
|
let imageName = isMutedThread ? "speaker" : "speaker.slash"
|
||||||
|
let unmuteThreadString = NSLocalizedString("Unmute conversation", comment: "Context menu option for unmuting a conversation.")
|
||||||
|
let muteThreadString = NSLocalizedString("Mute conversation", comment: "Context menu option for muting a conversation.")
|
||||||
|
Label(isMutedThread ? unmuteThreadString : muteThreadString, systemImage: imageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
NotificationCenter.default.post(name: .broadcast_event, object: event)
|
NotificationCenter.default.post(name: .broadcast_event, object: event)
|
||||||
} label: {
|
} label: {
|
||||||
@@ -104,7 +124,7 @@ struct MenuItems: View {
|
|||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
notify(.mute, target_pubkey)
|
notify(.mute, target_pubkey)
|
||||||
} label: {
|
} label: {
|
||||||
Label(NSLocalizedString("Mute", comment: "Context menu option for muting users."), systemImage: "exclamationmark.octagon")
|
Label(NSLocalizedString("Mute User", comment: "Context menu option for muting users."), systemImage: "exclamationmark.octagon")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct SelectedEventView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks)
|
EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks, muted_threads: damus.muted_threads)
|
||||||
.padding([.bottom], 4)
|
.padding([.bottom], 4)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ struct TextEvent: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ContextButton: some View {
|
var ContextButton: some View {
|
||||||
EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks)
|
EventMenuContext(event: event, keypair: damus.keypair, target_pubkey: event.pubkey, bookmarks: damus.bookmarks, muted_threads: damus.muted_threads)
|
||||||
.padding([.bottom], 4)
|
.padding([.bottom], 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,13 +96,13 @@ struct NotificationsView: View {
|
|||||||
}
|
}
|
||||||
.coordinateSpace(name: "scroll")
|
.coordinateSpace(name: "scroll")
|
||||||
.onReceive(handle_notify(.scroll_to_top)) { notif in
|
.onReceive(handle_notify(.scroll_to_top)) { notif in
|
||||||
let _ = notifications.flush()
|
let _ = notifications.flush(state)
|
||||||
self.notifications.should_queue = false
|
self.notifications.should_queue = false
|
||||||
scroll_to_event(scroller: scroller, id: "startblock", delay: 0.0, animate: true, anchor: .top)
|
scroll_to_event(scroller: scroller, id: "startblock", delay: 0.0, animate: true, anchor: .top)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
let _ = notifications.flush()
|
let _ = notifications.flush(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ struct SearchHomeView: View {
|
|||||||
damus: damus_state,
|
damus: damus_state,
|
||||||
show_friend_icon: true,
|
show_friend_icon: true,
|
||||||
filter: {
|
filter: {
|
||||||
|
if damus_state.muted_threads.isMutedThread($0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if damus_state.settings.show_only_preferred_languages == false {
|
if damus_state.settings.show_only_preferred_languages == false {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user