feat: 💨
This commit is contained in:
@@ -8,6 +8,7 @@ export const StorageKey = {
|
||||
ACCOUNT_RELAY_LIST_EVENT_MAP: 'accountRelayListEventMap',
|
||||
ACCOUNT_FOLLOW_LIST_EVENT_MAP: 'accountFollowListEventMap',
|
||||
ACCOUNT_MUTE_LIST_EVENT_MAP: 'accountMuteListEventMap',
|
||||
ACCOUNT_MUTE_DECRYPTED_TAGS_MAP: 'accountMuteDecryptedTagsMap',
|
||||
ACCOUNT_PROFILE_EVENT_MAP: 'accountProfileEventMap',
|
||||
ADD_CLIENT_TAG: 'addClientTag'
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ export default function SettingsPage({ index }: { index?: number }) {
|
||||
}
|
||||
|
||||
const SettingItem = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
|
||||
({ children, className, ...props }) => {
|
||||
({ children, className, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -123,6 +123,7 @@ const SettingItem = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -30,28 +30,6 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
|
||||
const [tags, setTags] = useState<string[][]>([])
|
||||
const mutePubkeys = useMemo(() => extractPubkeysFromEventTags(tags), [tags])
|
||||
|
||||
useEffect(() => {
|
||||
if (!muteListEvent) {
|
||||
setTags([])
|
||||
return
|
||||
}
|
||||
|
||||
const updateTags = async () => {
|
||||
const tags = muteListEvent.tags
|
||||
if (muteListEvent.content && accountPubkey) {
|
||||
try {
|
||||
const plainText = await nip04Decrypt(accountPubkey, muteListEvent.content)
|
||||
const contentTags = z.array(z.array(z.string())).parse(JSON.parse(plainText))
|
||||
tags.push(...contentTags.filter((tag) => tags.every((t) => !isSameTag(t, tag))))
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
setTags(tags)
|
||||
}
|
||||
updateTags()
|
||||
}, [muteListEvent])
|
||||
|
||||
useEffect(() => {
|
||||
if (!accountPubkey) return
|
||||
|
||||
@@ -60,6 +38,8 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
|
||||
const storedMuteListEvent = storage.getAccountMuteListEvent(accountPubkey)
|
||||
if (storedMuteListEvent) {
|
||||
setMuteListEvent(storedMuteListEvent)
|
||||
const tags = await extractMuteTags(storedMuteListEvent)
|
||||
setTags(tags)
|
||||
}
|
||||
const events = await client.fetchEvents(relayList?.write ?? client.getDefaultRelayUrls(), {
|
||||
kinds: [kinds.Mutelist],
|
||||
@@ -68,16 +48,41 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
|
||||
const muteEvent = getLatestEvent(events) as Event | undefined
|
||||
if (muteEvent) {
|
||||
setMuteListEvent(muteEvent)
|
||||
const tags = await extractMuteTags(muteEvent)
|
||||
setTags(tags)
|
||||
}
|
||||
}
|
||||
|
||||
init()
|
||||
}, [accountPubkey])
|
||||
|
||||
const updateMuteListEvent = (event: Event) => {
|
||||
const extractMuteTags = async (muteListEvent: Event) => {
|
||||
const tags = [...muteListEvent.tags]
|
||||
if (muteListEvent.content) {
|
||||
const storedDecryptedTags = storage.getAccountMuteDecryptedTags(muteListEvent)
|
||||
|
||||
if (storedDecryptedTags) {
|
||||
tags.push(...storedDecryptedTags)
|
||||
} else {
|
||||
try {
|
||||
const plainText = await nip04Decrypt(muteListEvent.pubkey, muteListEvent.content)
|
||||
const contentTags = z.array(z.array(z.string())).parse(JSON.parse(plainText))
|
||||
storage.setAccountMuteDecryptedTags(muteListEvent, contentTags)
|
||||
tags.push(...contentTags.filter((tag) => tags.every((t) => !isSameTag(t, tag))))
|
||||
} catch (error) {
|
||||
console.error('Failed to decrypt mute list content', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
const update = (event: Event, tags: string[][]) => {
|
||||
const isNew = storage.setAccountMuteListEvent(event)
|
||||
if (!isNew) return
|
||||
storage.setAccountMuteDecryptedTags(event, tags)
|
||||
setMuteListEvent(event)
|
||||
setTags(tags)
|
||||
}
|
||||
|
||||
const mutePubkey = async (pubkey: string) => {
|
||||
@@ -87,7 +92,7 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
|
||||
const cipherText = await nip04Encrypt(accountPubkey, JSON.stringify(newTags))
|
||||
const newMuteListDraftEvent = createMuteListDraftEvent(muteListEvent?.tags ?? [], cipherText)
|
||||
const newMuteListEvent = await publish(newMuteListDraftEvent)
|
||||
updateMuteListEvent(newMuteListEvent)
|
||||
update(newMuteListEvent, newTags)
|
||||
}
|
||||
|
||||
const unmutePubkey = async (pubkey: string) => {
|
||||
@@ -100,7 +105,7 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
|
||||
cipherText
|
||||
)
|
||||
const newMuteListEvent = await publish(newMuteListDraftEvent)
|
||||
updateMuteListEvent(newMuteListEvent)
|
||||
update(newMuteListEvent, newTags)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -29,6 +29,10 @@ class StorageService {
|
||||
private accountRelayListEventMap: Record<string, Event | undefined> = {} // pubkey -> relayListEvent
|
||||
private accountFollowListEventMap: Record<string, Event | undefined> = {} // pubkey -> followListEvent
|
||||
private accountMuteListEventMap: Record<string, Event | undefined> = {} // pubkey -> muteListEvent
|
||||
private accountMuteDecryptedTagsMap: Record<
|
||||
string,
|
||||
{ id: string; tags: string[][] } | undefined
|
||||
> = {} // pubkey -> { id, tags }
|
||||
private accountProfileEventMap: Record<string, Event | undefined> = {} // pubkey -> profileEvent
|
||||
|
||||
constructor() {
|
||||
@@ -67,6 +71,12 @@ class StorageService {
|
||||
this.accountMuteListEventMap = accountMuteListEventMapStr
|
||||
? JSON.parse(accountMuteListEventMapStr)
|
||||
: {}
|
||||
const accountMuteDecryptedTagsMapStr = window.localStorage.getItem(
|
||||
StorageKey.ACCOUNT_MUTE_DECRYPTED_TAGS_MAP
|
||||
)
|
||||
this.accountMuteDecryptedTagsMap = accountMuteDecryptedTagsMapStr
|
||||
? JSON.parse(accountMuteDecryptedTagsMapStr)
|
||||
: {}
|
||||
const accountProfileEventMapStr = window.localStorage.getItem(
|
||||
StorageKey.ACCOUNT_PROFILE_EVENT_MAP
|
||||
)
|
||||
@@ -184,6 +194,7 @@ class StorageService {
|
||||
delete this.accountFollowListEventMap[account.pubkey]
|
||||
delete this.accountRelayListEventMap[account.pubkey]
|
||||
delete this.accountMuteListEventMap[account.pubkey]
|
||||
delete this.accountMuteDecryptedTagsMap[account.pubkey]
|
||||
delete this.accountProfileEventMap[account.pubkey]
|
||||
window.localStorage.setItem(StorageKey.ACCOUNTS, JSON.stringify(this.accounts))
|
||||
window.localStorage.setItem(
|
||||
@@ -194,6 +205,10 @@ class StorageService {
|
||||
StorageKey.ACCOUNT_MUTE_LIST_EVENT_MAP,
|
||||
JSON.stringify(this.accountMuteListEventMap)
|
||||
)
|
||||
window.localStorage.setItem(
|
||||
StorageKey.ACCOUNT_MUTE_DECRYPTED_TAGS_MAP,
|
||||
JSON.stringify(this.accountMuteDecryptedTagsMap)
|
||||
)
|
||||
window.localStorage.setItem(
|
||||
StorageKey.ACCOUNT_RELAY_LIST_EVENT_MAP,
|
||||
JSON.stringify(this.accountRelayListEventMap)
|
||||
@@ -276,6 +291,22 @@ class StorageService {
|
||||
return true
|
||||
}
|
||||
|
||||
getAccountMuteDecryptedTags(muteListEvent: Event) {
|
||||
const stored = this.accountMuteDecryptedTagsMap[muteListEvent.pubkey]
|
||||
if (stored && stored.id === muteListEvent.id) {
|
||||
return stored.tags
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
setAccountMuteDecryptedTags(muteListEvent: Event, tags: string[][]) {
|
||||
this.accountMuteDecryptedTagsMap[muteListEvent.pubkey] = { id: muteListEvent.id, tags }
|
||||
window.localStorage.setItem(
|
||||
StorageKey.ACCOUNT_MUTE_DECRYPTED_TAGS_MAP,
|
||||
JSON.stringify(this.accountMuteDecryptedTagsMap)
|
||||
)
|
||||
}
|
||||
|
||||
getAccountProfileEvent(pubkey: string) {
|
||||
return this.accountProfileEventMap[pubkey]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user