diff --git a/CHANGELOG.md b/CHANGELOG.md index e7c8bcb4..13008a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - [x] Make "show new notes" button fixed position - [x] Gray out buttons that don't work when logged in with pubkey +- [x] Clean up popovers, re-design notes on small screens +- [x] Migrate muffle to mute, add thread muting ## 0.2.16 diff --git a/ROADMAP.md b/ROADMAP.md index 42565e68..c4037fc1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,8 @@ # Current +- [ ] Check mention interpolation indexes nevent1qqsx27cspgfcj93kryt2zpzzt5ua60rtucckvcmsrqc949e6t83jaxspzemhxue69uhhyetvv9ujumn0wd68ytnzv9hxg46e8sv +- [ ] Muffle -> mute + - Add mute button on profile - [ ] Show loading/success on zap invoice screen - [ ] Fix iOS/safari/firefox - [ ] Update https://nostr.com/clients/coracle diff --git a/src/App.svelte b/src/App.svelte index 8af64093..878ccd46 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -60,7 +60,6 @@ import NoteDetail from "src/views/notes/NoteDetail.svelte" import PersonList from "src/views/person/PersonList.svelte" import PersonProfileInfo from "src/views/person/PersonProfileInfo.svelte" - import PersonSettings from "src/views/person/PersonSettings.svelte" import PersonShare from "src/views/person/PersonShare.svelte" import AddRelay from "src/views/relays/AddRelay.svelte" import RelayCard from "src/views/relays/RelayCard.svelte" @@ -250,8 +249,6 @@ {:else if $modal.type === "login/connect"} - {:else if $modal.type === "person/settings"} - {:else if $modal.type === "person/info"} {:else if $modal.type === "person/share"} diff --git a/src/agent/cmd.ts b/src/agent/cmd.ts index e9b490ef..5857648f 100644 --- a/src/agent/cmd.ts +++ b/src/agent/cmd.ts @@ -26,8 +26,8 @@ const setRelays = newRelays => const setPetnames = petnames => new PublishableEvent(3, {tags: petnames}) -const muffle = muffle => - new PublishableEvent(12165, {tags: muffle}) +const setMutes = mutes => + new PublishableEvent(10000, {tags: mutes}) const createRoom = room => new PublishableEvent(40, {content: JSON.stringify(pick(roomAttrs, room))}) @@ -132,7 +132,7 @@ class PublishableEvent { } export default { - updateUser, setRelays, setPetnames, muffle, createRoom, updateRoom, + updateUser, setRelays, setPetnames, setMutes, createRoom, updateRoom, createChatMessage, createDirectMessage, createNote, createReaction, createReply, requestZap, deleteEvent, PublishableEvent, } diff --git a/src/agent/sync.ts b/src/agent/sync.ts index 0436bc4e..d57ae790 100644 --- a/src/agent/sync.ts +++ b/src/agent/sync.ts @@ -96,7 +96,23 @@ const processProfileEvents = async events => { return data }, - 12165: () => ({muffle: e.tags}), + 10000: () => { + if (e.created_at > (person.mutes_updated_at || 0)) { + return { + mutes_updated_at: e.created_at, + mutes: e.tags, + } + } + }, + // DEPRECATED + 12165: () => { + if (e.created_at > (person.mutes_updated_at || 0)) { + return { + mutes_updated_at: e.created_at, + mutes: e.tags, + } + } + }, // DEPRECATED 10001: () => { if (e.created_at > (person.relays_updated_at || 0)) { diff --git a/src/agent/user.ts b/src/agent/user.ts index 45ad55c5..61d62ed6 100644 --- a/src/agent/user.ts +++ b/src/agent/user.ts @@ -1,8 +1,8 @@ import type {Person} from 'src/util/types' import type {Readable} from 'svelte/store' -import {last, prop, find, pipe, assoc, whereEq, when, concat, reject, nth, map} from 'ramda' +import {slice, identity, prop, find, pipe, assoc, whereEq, when, concat, reject, nth, map} from 'ramda' +import {findReplyId, findRootId} from 'src/util/nostr' import {synced} from 'src/util/misc' -import {Tags} from 'src/util/nostr' import {derived} from 'svelte/store' import database from 'src/agent/database' import keys from 'src/agent/keys' @@ -19,9 +19,11 @@ let settingsCopy = null let profileCopy = null let petnamesCopy = [] let relaysCopy = [] +let mutesCopy = [] const anonPetnames = synced('agent/user/anonPetnames', []) const anonRelays = synced('agent/user/anonRelays', []) +const anonMutes = synced('agent/user/anonMutes', []) const settings = synced("agent/user/settings", { relayLimit: 20, @@ -42,17 +44,17 @@ const profile = derived( } ) as Readable -const petnames = derived( - [profile, anonPetnames], - ([$profile, $anonPetnames]) => - $profile?.petnames || $anonPetnames +const profileKeyWithDefault = (key, stores) => derived( + [profile, ...stores], + ([$profile, ...values]) => + $profile?.[key] || find(identity, values) ) -const relays = derived( - [profile, anonRelays], - ([$profile, $anonRelays]) => - $profile?.relays || $anonRelays -) +const petnames = profileKeyWithDefault('petnames', [anonPetnames]) +const relays = profileKeyWithDefault('relays', [anonRelays]) + +// Backwards compat, migrate muffle to mute temporarily +const mutes = profileKeyWithDefault('mutes', [anonMutes, derived(profile, prop('muffle'))]) const canPublish = derived( [keys.pubkey, relays], @@ -74,6 +76,10 @@ petnames.subscribe($petnames => { petnamesCopy = $petnames }) +mutes.subscribe($mutes => { + mutesCopy = $mutes +}) + relays.subscribe($relays => { relaysCopy = $relays }) @@ -92,34 +98,6 @@ const user = { canPublish, getProfile: () => profileCopy, getPubkey: () => profileCopy?.pubkey, - muffle: events => { - const muffle = user.getMuffle() - - return events.filter(e => !muffle.has(e.pubkey)) - }, - getMuffle: () => { - return new Set( - Tags - .wrap((profileCopy?.muffle || [])) - .filter(t => Math.random() > parseFloat(last(t))) - .values() - .all() - ) - }, - mute: events => { - const mutes = user.getMutes() - - return events.filter(e => !mutes.has(e.pubkey)) - }, - getMutes: () => { - return new Set( - Tags - .wrap((profileCopy?.muffle || [])) - .filter(t => parseFloat(last(t)) === 0) - .values() - .all() - ) - }, // Petnames @@ -166,6 +144,39 @@ const user = { setRelayWriteCondition(url, write) { return this.updateRelays(map(when(whereEq({url}), assoc('write', write)))) }, + + // Mutes + + mutes, + getMutes: () => mutesCopy, + applyMutes: events => { + const m = new Set(mutesCopy.map(m => m[1])) + + return events.filter(e => + !(m.has(e.id) || m.has(e.pubkey) || m.has(findReplyId(e)) || m.has(findRootId(e))) + ) + }, + updateMutes(f) { + const $mutes = f(mutesCopy) + console.log(mutesCopy, $mutes) + + anonMutes.set($mutes) + + if (profileCopy) { + return cmd.setMutes($mutes.map(slice(0, 2))).publish(relaysCopy) + } + }, + addMute(type, value) { + return this.updateMutes( + pipe( + reject(t => t[1] === value), + concat([[type, value]]) + ) + ) + }, + removeMute(pubkey) { + return this.updateMutes(reject(t => t[1] === pubkey)) + }, } export default user diff --git a/src/routes/Alerts.svelte b/src/routes/Alerts.svelte index 24159981..203a5d2a 100644 --- a/src/routes/Alerts.svelte +++ b/src/routes/Alerts.svelte @@ -1,5 +1,5 @@ - -
- -
-

Advanced Follow

-

Fine grained controls for interacting with other people.

-
-
- How often do you want to see notes from this person? - -

- "Never" is effectively a mute, while "Always" will show posts whenever available. If you - want a middle ground, choose "Sometimes" or "Often". -

-
- -
-