mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
mute: migrating muted_threads to new mute list
This patch depends on: Adding ability to mute hashtag from SearchView This is the last patch for the new mute list feature - Removing MutedThreadsManager - Adding system to migrate existing muted threads to new mute list Closes: https://github.com/damus-io/damus/issues/1718 Closes: https://github.com/damus-io/damus/issues/856 Lighting Address: fishcharlie@strike.me Signed-off-by: Charlie Fish <contact@charlie.fish> Reviewed-by: William Casarin <jb55@jb55.com> Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
89f7c3ff30
commit
71c9bd63fc
@ -11,7 +11,6 @@ struct NotificationExtensionState: HeadlessDamusState {
|
||||
let ndb: Ndb
|
||||
let settings: UserSettingsStore
|
||||
let contacts: Contacts
|
||||
let muted_threads: MutedThreadsManager
|
||||
let keypair: Keypair
|
||||
let profiles: Profiles
|
||||
let zaps: Zaps
|
||||
@ -28,7 +27,6 @@ struct NotificationExtensionState: HeadlessDamusState {
|
||||
self.settings = UserSettingsStore()
|
||||
|
||||
self.contacts = Contacts(our_pubkey: keypair.pubkey)
|
||||
self.muted_threads = MutedThreadsManager(keypair: keypair)
|
||||
self.keypair = keypair
|
||||
self.profiles = Profiles(ndb: ndb)
|
||||
self.zaps = Zaps(our_pubkey: keypair.pubkey)
|
||||
|
@ -510,7 +510,6 @@
|
||||
D7CB5D402B116E8A00AD4105 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
||||
D7CB5D412B116F0900AD4105 /* StringCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5588229F33F5B00DC6A45 /* StringCodable.swift */; };
|
||||
D7CB5D422B116F8900AD4105 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79A28306D7B00E1F516 /* Contacts.swift */; };
|
||||
D7CB5D432B116F9B00AD4105 /* MutedThreadsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A48E7AF29DFBE9D006E787E /* MutedThreadsManager.swift */; };
|
||||
D7CB5D452B116FE800AD4105 /* Contacts+.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CB5D442B116FE800AD4105 /* Contacts+.swift */; };
|
||||
D7CB5D462B11703D00AD4105 /* Notify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA3529F2A76AE80003BB08B /* Notify.swift */; };
|
||||
D7CB5D472B11718700AD4105 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
||||
@ -3530,7 +3529,6 @@
|
||||
D7CCFC0F2B0587F600323D86 /* Keys.swift in Sources */,
|
||||
D7CB5D542B1174F700AD4105 /* NIP05.swift in Sources */,
|
||||
D798D2232B0859B700234419 /* KeychainStorage.swift in Sources */,
|
||||
D7CB5D432B116F9B00AD4105 /* MutedThreadsManager.swift in Sources */,
|
||||
D74AAFC32B153395006CF0F4 /* HeadlessDamusState.swift in Sources */,
|
||||
D7CE1B272B0BE224002EDAD4 /* bech32_util.c in Sources */,
|
||||
D7CCFC102B05880F00323D86 /* Id.swift in Sources */,
|
||||
|
@ -674,7 +674,6 @@ struct ContentView: View {
|
||||
postbox: PostBox(pool: pool),
|
||||
bootstrap_relays: bootstrap_relays,
|
||||
replies: ReplyCounter(our_pubkey: pubkey),
|
||||
muted_threads: MutedThreadsManager(keypair: keypair),
|
||||
wallet: WalletModel(settings: settings),
|
||||
nav: self.navigationCoordinator,
|
||||
music: MusicController(onChange: music_changed),
|
||||
|
@ -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(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: inner_ev)
|
||||
return should_show_event(contacts: damus_state.contacts, ev: inner_ev)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ struct DamusState: HeadlessDamusState {
|
||||
let postbox: PostBox
|
||||
let bootstrap_relays: [String]
|
||||
let replies: ReplyCounter
|
||||
let muted_threads: MutedThreadsManager
|
||||
let wallet: WalletModel
|
||||
let nav: NavigationCoordinator
|
||||
let music: MusicController?
|
||||
@ -36,7 +35,7 @@ struct DamusState: HeadlessDamusState {
|
||||
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, muted_threads: MutedThreadsManager, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil) {
|
||||
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) {
|
||||
self.pool = pool
|
||||
self.keypair = keypair
|
||||
self.likes = likes
|
||||
@ -56,7 +55,6 @@ struct DamusState: HeadlessDamusState {
|
||||
self.postbox = postbox
|
||||
self.bootstrap_relays = bootstrap_relays
|
||||
self.replies = replies
|
||||
self.muted_threads = muted_threads
|
||||
self.wallet = wallet
|
||||
self.nav = nav
|
||||
self.music = music
|
||||
@ -123,7 +121,6 @@ struct DamusState: HeadlessDamusState {
|
||||
postbox: PostBox(pool: RelayPool(ndb: .empty)),
|
||||
bootstrap_relays: [],
|
||||
replies: ReplyCounter(our_pubkey: empty_pub),
|
||||
muted_threads: MutedThreadsManager(keypair: kp),
|
||||
wallet: WalletModel(settings: UserSettingsStore()),
|
||||
nav: NavigationCoordinator(),
|
||||
music: nil,
|
||||
|
@ -15,7 +15,6 @@ protocol HeadlessDamusState {
|
||||
var ndb: Ndb { get }
|
||||
var settings: UserSettingsStore { get }
|
||||
var contacts: Contacts { get }
|
||||
var muted_threads: MutedThreadsManager { get }
|
||||
var keypair: Keypair { get }
|
||||
var profiles: Profiles { get }
|
||||
var zaps: Zaps { get }
|
||||
|
@ -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(keypair: self.damus_state.keypair, hellthreads: self.damus_state.muted_threads, contacts: self.damus_state.contacts, ev: zap.request.ev) else {
|
||||
should_show_event(contacts: self.damus_state.contacts, ev: zap.request.ev) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -577,6 +577,8 @@ class HomeModel {
|
||||
}
|
||||
|
||||
damus_state.contacts.set_mutelist(ev)
|
||||
|
||||
migrate_old_muted_threads_to_new_mutelist(keypair: damus_state.keypair, damus_state: damus_state)
|
||||
}
|
||||
|
||||
func handle_old_list_event(_ ev: NostrEvent) {
|
||||
@ -597,6 +599,8 @@ class HomeModel {
|
||||
}
|
||||
|
||||
damus_state.contacts.set_mutelist(ev)
|
||||
|
||||
migrate_old_muted_threads_to_new_mutelist(keypair: damus_state.keypair, damus_state: damus_state)
|
||||
}
|
||||
|
||||
func get_last_event_of_kind(relay_id: String, kind: UInt32) -> NostrEvent? {
|
||||
@ -612,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(keypair: self.damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: ev) else {
|
||||
should_show_event(contacts: damus_state.contacts, ev: ev) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -650,7 +654,7 @@ class HomeModel {
|
||||
|
||||
|
||||
func handle_text_event(sub_id: String, _ ev: NostrEvent) {
|
||||
guard should_show_event(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: ev) else {
|
||||
guard should_show_event(contacts: damus_state.contacts, ev: ev) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -679,7 +683,7 @@ class HomeModel {
|
||||
}
|
||||
|
||||
func handle_dm(_ ev: NostrEvent) {
|
||||
guard should_show_event(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: ev) else {
|
||||
guard should_show_event(contacts: damus_state.contacts, ev: ev) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1086,14 +1090,12 @@ 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(
|
||||
keypair: damus_state.keypair,
|
||||
hellthreads: damus_state.muted_threads,
|
||||
contacts: damus_state.contacts,
|
||||
ev: event
|
||||
)
|
||||
}
|
||||
|
||||
func should_show_event(keypair: Keypair, hellthreads: MutedThreadsManager, contacts: Contacts, ev: NostrEvent) -> Bool {
|
||||
func should_show_event(contacts: Contacts, ev: NostrEvent) -> Bool {
|
||||
let event_muted = contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil
|
||||
if event_muted {
|
||||
return false
|
||||
|
@ -11,7 +11,7 @@ fileprivate func getMutedThreadsKey(pubkey: Pubkey) -> String {
|
||||
pk_setting_key(pubkey, key: "muted_threads")
|
||||
}
|
||||
|
||||
func loadMutedThreads(pubkey: Pubkey) -> [NoteId] {
|
||||
func loadOldMutedThreads(pubkey: Pubkey) -> [NoteId] {
|
||||
let key = getMutedThreadsKey(pubkey: pubkey)
|
||||
let xs = UserDefaults.standard.stringArray(forKey: key) ?? []
|
||||
return xs.reduce(into: [NoteId]()) { ids, k in
|
||||
@ -20,56 +20,20 @@ func loadMutedThreads(pubkey: Pubkey) -> [NoteId] {
|
||||
}
|
||||
}
|
||||
|
||||
func saveMutedThreads(pubkey: Pubkey, currentValue: [NoteId], value: [NoteId]) -> Bool {
|
||||
let uniqueMutedThreads = Array(Set(value))
|
||||
|
||||
if uniqueMutedThreads != currentValue {
|
||||
let ids = uniqueMutedThreads.map { note_id in return note_id.hex() }
|
||||
UserDefaults.standard.set(ids, forKey: getMutedThreadsKey(pubkey: pubkey))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
class MutedThreadsManager: ObservableObject {
|
||||
|
||||
private let keypair: Keypair
|
||||
|
||||
private var _mutedThreadsSet: Set<NoteId>
|
||||
private var _mutedThreads: [NoteId]
|
||||
var mutedThreads: [NoteId] {
|
||||
get {
|
||||
return _mutedThreads
|
||||
}
|
||||
set {
|
||||
if saveMutedThreads(pubkey: keypair.pubkey, currentValue: _mutedThreads, value: newValue) {
|
||||
self._mutedThreads = newValue
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(keypair: Keypair) {
|
||||
self._mutedThreads = loadMutedThreads(pubkey: keypair.pubkey)
|
||||
self._mutedThreadsSet = Set(_mutedThreads)
|
||||
self.keypair = keypair
|
||||
}
|
||||
|
||||
func isMutedThread(_ ev: NostrEvent, keypair: Keypair) -> Bool {
|
||||
return _mutedThreadsSet.contains(ev.thread_id(keypair: keypair))
|
||||
}
|
||||
|
||||
func updateMutedThread(_ ev: NostrEvent) {
|
||||
let threadId = ev.thread_id(keypair: keypair)
|
||||
if isMutedThread(ev, keypair: keypair) {
|
||||
mutedThreads = mutedThreads.filter { $0 != threadId }
|
||||
_mutedThreadsSet.remove(threadId)
|
||||
notify(.unmute_thread(ev))
|
||||
} else {
|
||||
mutedThreads.append(threadId)
|
||||
_mutedThreadsSet.insert(threadId)
|
||||
notify(.mute_thread(ev))
|
||||
}
|
||||
}
|
||||
// We need to still use it since existing users might have their muted threads stored in UserDefaults
|
||||
// So now all it's doing is moving a users muted threads to the new kind:10000 system
|
||||
// It should not be used for any purpose beyond that
|
||||
func migrate_old_muted_threads_to_new_mutelist(keypair: Keypair, damus_state: DamusState) {
|
||||
// Ensure that keypair is fullkeypair
|
||||
guard let fullKeypair = keypair.to_full() else { return }
|
||||
// Load existing muted threads
|
||||
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
|
||||
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.postbox.send(new_mutelist_event)
|
||||
// Set existing muted threads to an empty array
|
||||
UserDefaults.standard.set([], forKey: getMutedThreadsKey(pubkey: keypair.pubkey))
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class SearchHomeModel: ObservableObject {
|
||||
}
|
||||
|
||||
func filter_muted() {
|
||||
events.filter { should_show_event(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: $0) }
|
||||
events.filter { should_show_event(contacts: damus_state.contacts, 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(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: ev) && !ev.is_reply(damus_state.keypair)
|
||||
if ev.is_textlike && should_show_event(contacts: damus_state.contacts, ev: ev) && !ev.is_reply(damus_state.keypair)
|
||||
{
|
||||
if !damus_state.settings.multiple_events_per_pubkey && seen_pubkey.contains(ev.pubkey) {
|
||||
return
|
||||
|
@ -28,7 +28,7 @@ class SearchModel: ObservableObject {
|
||||
|
||||
func filter_muted() {
|
||||
self.events.filter {
|
||||
should_show_event(keypair: state.keypair, hellthreads: state.muted_threads, contacts: state.contacts, ev: $0)
|
||||
should_show_event(contacts: state.contacts, ev: $0)
|
||||
}
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
@ -57,7 +57,7 @@ class SearchModel: ObservableObject {
|
||||
return
|
||||
}
|
||||
|
||||
guard should_show_event(keypair: state.keypair, hellthreads: state.muted_threads, contacts: state.contacts, ev: ev) else {
|
||||
guard should_show_event(contacts: state.contacts, ev: ev) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ var test_damus_state: DamusState = ({
|
||||
postbox: .init(pool: pool),
|
||||
bootstrap_relays: .init(),
|
||||
replies: .init(our_pubkey: our_pubkey),
|
||||
muted_threads: .init(keypair: test_keypair),
|
||||
wallet: .init(settings: settings),
|
||||
nav: .init(),
|
||||
music: .init(onChange: {_ in }),
|
||||
|
@ -27,7 +27,7 @@ struct EventMutingContainerView<Content: View>: View {
|
||||
self.damus_state = damus_state
|
||||
self.event = event
|
||||
self.content = content()
|
||||
self._shown = State(initialValue: should_show_event(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: event))
|
||||
self._shown = State(initialValue: should_show_event(contacts: damus_state.contacts, ev: event))
|
||||
}
|
||||
|
||||
init(damus_state: DamusState, event: NostrEvent, muteBox: @escaping MuteBoxViewClosure, @ViewBuilder content: () -> Content) {
|
||||
@ -36,7 +36,7 @@ struct EventMutingContainerView<Content: View>: View {
|
||||
}
|
||||
|
||||
var should_mute: Bool {
|
||||
return !should_show_event(keypair: damus_state.keypair, hellthreads: damus_state.muted_threads, contacts: damus_state.contacts, ev: event)
|
||||
return !should_show_event(contacts: damus_state.contacts, ev: event)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
@ -59,7 +59,8 @@ struct SearchHomeView: View {
|
||||
return false
|
||||
}
|
||||
|
||||
if damus_state.muted_threads.isMutedThread(ev, keypair: self.damus_state.keypair) {
|
||||
let event_muted = damus_state.contacts.mutelist?.mute_list?.event_muted_reason(ev) != nil
|
||||
if event_muted {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ final class LongPostTests: XCTestCase {
|
||||
XCTAssertEqual(subid, "subid")
|
||||
XCTAssertTrue(ev.should_show_event)
|
||||
XCTAssertTrue(!ev.too_big)
|
||||
XCTAssertTrue(should_show_event(keypair: test_keypair, hellthreads: test_damus_state.muted_threads, contacts: contacts, ev: ev))
|
||||
XCTAssertTrue(should_show_event(contacts: contacts, ev: ev))
|
||||
XCTAssertTrue(validate_event(ev: ev) == .ok )
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@ func generate_test_damus_state(
|
||||
postbox: .init(pool: pool),
|
||||
bootstrap_relays: .init(),
|
||||
replies: .init(our_pubkey: our_pubkey),
|
||||
muted_threads: .init(keypair: test_keypair),
|
||||
wallet: .init(settings: settings),
|
||||
nav: .init(),
|
||||
music: .init(onChange: {_ in }),
|
||||
|
Loading…
Reference in New Issue
Block a user