mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Remember which rooms the user has joined
This commit is contained in:
parent
7916ed501c
commit
612a0d18df
@ -15,6 +15,7 @@ export const loki = new Loki("agent.db", {
|
||||
autoload: true,
|
||||
autosave: true,
|
||||
autosaveInterval: 4000,
|
||||
throttledSaves: true,
|
||||
adapter: new Adapter(),
|
||||
autoloadCallback: () => {
|
||||
for (const table of Object.values(registry)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {uniq, prop, reject, nth, uniqBy, objOf, pick, identity} from "ramda"
|
||||
import {is, uniq, prop, reject, nth, uniqBy, objOf, pick, identity} from "ramda"
|
||||
import {nip05} from "nostr-tools"
|
||||
import {noop, ensurePlural, chunk} from "hurdak/lib/hurdak"
|
||||
import {
|
||||
@ -242,16 +242,30 @@ addHandler(
|
||||
30078,
|
||||
profileHandler("settings", async (e, p) => {
|
||||
if (Tags.from(e).getMeta("d") === "coracle/settings/v1") {
|
||||
return keys.decryptJson(e.content)
|
||||
return {...p.settings, ...(await keys.decryptJson(e.content))}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
addHandler(
|
||||
30078,
|
||||
profileHandler("lastChecked", async (e, p) => {
|
||||
profileHandler("last_checked", async (e, p) => {
|
||||
if (Tags.from(e).getMeta("d") === "coracle/last_checked/v1") {
|
||||
return {...p.lastChecked, ...(await keys.decryptJson(e.content))}
|
||||
return {...p.last_checked, ...(await keys.decryptJson(e.content))}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
addHandler(
|
||||
30078,
|
||||
profileHandler("rooms_joined", async (e, p) => {
|
||||
if (Tags.from(e).getMeta("d") === "coracle/rooms_joined/v1") {
|
||||
const roomsJoined = await keys.decryptJson(e.content)
|
||||
|
||||
// Just a bug from when I was building the feature, remove someday
|
||||
if (is(Array, roomsJoined)) {
|
||||
return roomsJoined
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
@ -3,6 +3,7 @@ import type {Readable} from "svelte/store"
|
||||
import {
|
||||
slice,
|
||||
uniqBy,
|
||||
without,
|
||||
reject,
|
||||
prop,
|
||||
find,
|
||||
@ -34,7 +35,8 @@ const profile = synced("agent/user/profile", {
|
||||
dufflepudUrl: import.meta.env.VITE_DUFFLEPUD_URL,
|
||||
multiplextrUrl: import.meta.env.VITE_MULTIPLEXTR_URL,
|
||||
},
|
||||
lastChecked: {},
|
||||
rooms_joined: [],
|
||||
last_checked: {},
|
||||
petnames: [],
|
||||
relays: [],
|
||||
mutes: [],
|
||||
@ -42,7 +44,8 @@ const profile = synced("agent/user/profile", {
|
||||
})
|
||||
|
||||
const settings = derived(profile, prop("settings"))
|
||||
const lastChecked = derived(profile, prop("lastChecked")) as Readable<Record<string, number>>
|
||||
const roomsJoined = derived(profile, prop("rooms_joined")) as Readable<string>
|
||||
const lastChecked = derived(profile, prop("last_checked")) as Readable<Record<string, number>>
|
||||
const petnames = derived(profile, prop("petnames")) as Readable<Array<Array<string>>>
|
||||
const relays = derived(profile, prop("relays")) as Readable<Array<Relay>>
|
||||
const mutes = derived(profile, prop("mutes")) as Readable<Array<[string, string]>>
|
||||
@ -93,6 +96,7 @@ export default {
|
||||
// App data
|
||||
|
||||
lastChecked,
|
||||
roomsJoined,
|
||||
async setAppData(key, content) {
|
||||
if (keys.canSign()) {
|
||||
const d = `coracle/${key}`
|
||||
@ -103,11 +107,29 @@ export default {
|
||||
},
|
||||
setLastChecked(k, v) {
|
||||
profile.update($profile => {
|
||||
const lastChecked = {...$profile.lastChecked, [k]: v}
|
||||
const lastChecked = {...$profile.last_checked, [k]: v}
|
||||
|
||||
this.setAppData("last_checked/v1", lastChecked)
|
||||
|
||||
return {...$profile, lastChecked}
|
||||
return {...$profile, last_checked: lastChecked}
|
||||
})
|
||||
},
|
||||
joinRoom(id) {
|
||||
profile.update($profile => {
|
||||
const roomsJoined = $profile.rooms_joined.concat(id)
|
||||
|
||||
this.setAppData("rooms_joined/v1", roomsJoined)
|
||||
|
||||
return {...$profile, rooms_joined: roomsJoined}
|
||||
})
|
||||
},
|
||||
leaveRoom(id) {
|
||||
profile.update($profile => {
|
||||
const roomsJoined = without([id], $profile.rooms_joined)
|
||||
|
||||
this.setAppData("rooms_joined/v1", roomsJoined)
|
||||
|
||||
return {...$profile, rooms_joined: roomsJoined}
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -102,7 +102,7 @@ export const newNotifications = derived(
|
||||
)
|
||||
|
||||
export const hasNewMessages = ({lastReceived, lastSent}, lastChecked) =>
|
||||
lastReceived > Math.max(lastSent, lastChecked || 0)
|
||||
lastReceived > Math.max(lastSent || lastReceived, lastChecked || 0)
|
||||
|
||||
export const newDirectMessages = derived(
|
||||
[watch("contacts", t => t.all()), user.lastChecked],
|
||||
@ -111,9 +111,14 @@ export const newDirectMessages = derived(
|
||||
)
|
||||
|
||||
export const newChatMessages = derived(
|
||||
[watch("rooms", t => t.all()), user.lastChecked],
|
||||
([rooms, $lastChecked]) =>
|
||||
Boolean(find(r => hasNewMessages(r, $lastChecked[`chat/${r.id}`]), rooms))
|
||||
[watch("rooms", t => t.all()), user.lastChecked, user.roomsJoined],
|
||||
([rooms, $lastChecked, $roomsJoined]) =>
|
||||
Boolean(
|
||||
find(
|
||||
r => $roomsJoined.includes(r.id) && hasNewMessages(r, $lastChecked[`chat/${r.id}`]),
|
||||
rooms
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Synchronization from events to state
|
||||
@ -159,10 +164,10 @@ const processChats = async (pubkey, events) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const listen = async pubkey => {
|
||||
// Include an offset so we don't miss notifications on one relay but not another
|
||||
export const listen = async () => {
|
||||
const pubkey = user.getPubkey()
|
||||
const {roomsJoined} = user.getProfile()
|
||||
const since = now() - timedelta(30, "days")
|
||||
const roomIds = pluck("id", rooms.all({joined: true}))
|
||||
const eventIds = doPipe(userEvents.all({kind: 1, created_at: {$gt: since}}), [
|
||||
sortBy(e => -e.created_at),
|
||||
slice(0, 256),
|
||||
@ -177,7 +182,7 @@ export const listen = async pubkey => {
|
||||
{kinds: [1, 4], authors: [pubkey], since},
|
||||
{kinds: [1, 7, 4, 9735], "#p": [pubkey], since},
|
||||
{kinds: [1, 7, 4, 9735], "#e": eventIds, since},
|
||||
{kinds: [42], "#e": roomIds, since},
|
||||
{kinds: [42], "#e": roomsJoined, since},
|
||||
],
|
||||
onChunk: async events => {
|
||||
events = user.applyMutes(events)
|
||||
@ -212,7 +217,7 @@ setInterval(() => {
|
||||
export const loadAppData = async pubkey => {
|
||||
if (getUserReadRelays().length > 0) {
|
||||
// Start our listener, but don't wait for it
|
||||
listen(pubkey)
|
||||
listen()
|
||||
|
||||
// Make sure the user and their network is loaded
|
||||
await network.loadPeople([pubkey], {force: true, kinds: userKinds})
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Button from "src/partials/Button.svelte"
|
||||
import {toast, modal} from "src/partials/state"
|
||||
import {getUserWriteRelays} from "src/agent/relays"
|
||||
import {rooms} from "src/agent/db"
|
||||
import user from "src/agent/user"
|
||||
import cmd from "src/agent/cmd"
|
||||
import {publishWithToast} from "src/app/state"
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
const [event] = await publishWithToast(relays, cmd.createRoom(room))
|
||||
|
||||
// Auto join the room the user just created
|
||||
rooms.patch({id: event.id, joined: true})
|
||||
user.joinRoom(event.id)
|
||||
}
|
||||
|
||||
modal.pop()
|
||||
|
@ -1,11 +1,14 @@
|
||||
<script>
|
||||
import {onMount} from "svelte"
|
||||
import {derived} from "svelte/store"
|
||||
import {partition} from "ramda"
|
||||
import {fuzzy} from "src/util/misc"
|
||||
import Input from "src/partials/Input.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import ChatListItem from "src/app/views/ChatListItem.svelte"
|
||||
import {watch} from "src/agent/db"
|
||||
import user from "src/agent/user"
|
||||
import network from "src/agent/network"
|
||||
import {getUserReadRelays} from "src/agent/relays"
|
||||
import {modal} from "src/partials/state"
|
||||
@ -14,10 +17,15 @@
|
||||
let search
|
||||
let results = []
|
||||
|
||||
const userRooms = watch("rooms", t => t.all({joined: true}))
|
||||
const otherRooms = watch("rooms", t => t.all({joined: {$ne: true}}))
|
||||
const {roomsJoined} = user
|
||||
const rooms = derived([watch("rooms", t => t.all()), roomsJoined], ([_rooms, _joined]) => {
|
||||
const ids = new Set(_joined)
|
||||
const [joined, other] = partition(r => ids.has(r.id), _rooms)
|
||||
|
||||
$: search = fuzzy($otherRooms, {keys: ["name", "about"]})
|
||||
return {joined, other}
|
||||
})
|
||||
|
||||
$: search = fuzzy($rooms.other, {keys: ["name", "about"]})
|
||||
$: results = search(q).slice(0, 50)
|
||||
|
||||
document.title = "Chat"
|
||||
@ -44,7 +52,7 @@
|
||||
<i class="fa-solid fa-plus" /> Create Room
|
||||
</Anchor>
|
||||
</div>
|
||||
{#each $userRooms as room (room.id)}
|
||||
{#each $rooms.joined as room (room.id)}
|
||||
<ChatListItem {room} />
|
||||
{:else}
|
||||
<p class="text-center py-8">You haven't yet joined any rooms.</p>
|
||||
@ -64,7 +72,7 @@
|
||||
<ChatListItem {room} />
|
||||
{/each}
|
||||
<small class="text-center">
|
||||
Showing {Math.min(50, $otherRooms.length)} of {$otherRooms.length} known rooms
|
||||
Showing {Math.min(50, $rooms.other.length)} of {$rooms.other.length} known rooms
|
||||
</small>
|
||||
{:else}
|
||||
<small class="text-center"> No matching rooms found </small>
|
||||
|
@ -4,13 +4,16 @@
|
||||
import {fly} from "svelte/transition"
|
||||
import {ellipsize} from "hurdak/lib/hurdak"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import {rooms} from "src/agent/db"
|
||||
import user from "src/agent/user"
|
||||
|
||||
export let room
|
||||
|
||||
const {roomsJoined} = user
|
||||
const enter = () => navigate(`/chat/${nip19.noteEncode(room.id)}`)
|
||||
const join = () => rooms.patch({id: room.id, joined: true})
|
||||
const leave = () => rooms.patch({id: room.id, joined: false})
|
||||
const join = () => user.joinRoom(room.id)
|
||||
const leave = () => user.leaveRoom(room.id)
|
||||
|
||||
$: joined = $roomsJoined.includes(room.id)
|
||||
</script>
|
||||
|
||||
<button
|
||||
@ -26,7 +29,7 @@
|
||||
<i class="fa fa-lock-open text-gray-1" />
|
||||
<h2 class="text-lg">{room.name || ""}</h2>
|
||||
</div>
|
||||
{#if room.joined}
|
||||
{#if joined}
|
||||
<Anchor type="button" preventDefault class="flex items-center gap-2" on:click={leave}>
|
||||
<i class="fa fa-right-from-bracket" />
|
||||
<span>Leave</span>
|
||||
|
@ -7,7 +7,11 @@ import {invoiceAmount} from "src/util/lightning"
|
||||
|
||||
export const personKinds = [0, 2, 3, 10001, 10002]
|
||||
export const userKinds = personKinds.concat([10000, 30001, 30078])
|
||||
export const appDataKeys = ["coracle/settings/v1", "coracle/last_checked/v1"]
|
||||
export const appDataKeys = [
|
||||
"coracle/settings/v1",
|
||||
"coracle/last_checked/v1",
|
||||
"coracle/rooms_joined/v1",
|
||||
]
|
||||
|
||||
export class Tags {
|
||||
tags: Array<any>
|
||||
|
Loading…
Reference in New Issue
Block a user