feat: show unread chat badges during video-only voice calls #276

Merged
hodlbod merged 1 commits from userAdityaa/flotilla:show-unread-chat-badges into dev 2026-05-19 15:36:22 +00:00
2 changed files with 36 additions and 6 deletions
+18 -4
View File
@@ -1,4 +1,4 @@
import {derived} from "svelte/store"
import {derived, get, writable} from "svelte/store"
import {Badge} from "@capawesome/capacitor-badge"
import {synced, throttled, withGetter} from "@welshman/store"
import {pubkey, tracker, repository, relaysByUrl} from "@welshman/app"
@@ -36,6 +36,9 @@ export const deriveChecked = (key: string) => derived(checked, prop<number>(key)
export const setChecked = (key: string) => checked.update(assoc(key, now()))
/** Room path while video call UI hides chat; checked + badge stay active until chat is shown. */
export const deferredRoomPath = writable<string | undefined>(undefined)
export const syncChecked = () => {
let prev = ""
@@ -57,8 +60,11 @@ export const syncChecked = () => {
// Set checked when we visit a given page - but delay it a tad
setTimeout(() => {
const defer = get(deferredRoomPath)
checked.update($checked => {
for (const path of getPaths($page.url.pathname)) {
if (defer && path === defer) continue
$checked[path] = now()
}
@@ -151,9 +157,17 @@ export const allNotifications = derived(
},
)
export const notifications = derived([page, allNotifications], ([$page, $allNotifications]) => {
return new Set([...$allNotifications].filter(p => !$page.url.pathname.startsWith(p)))
})
export const notifications = derived(
[page, allNotifications, deferredRoomPath],
([$page, $allNotifications, $deferredRoomPath]) =>
new Set(
[...$allNotifications].filter(p => {
if (!$page.url.pathname.startsWith(p)) return true
if ($deferredRoomPath && p === $deferredRoomPath) return true
return false
}),
),
)
// Badges
+18 -2
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import {onMount} from "svelte"
import {onDestroy, onMount} from "svelte"
import {readable} from "svelte/store"
import {page} from "$app/stores"
import {goto} from "$app/navigation"
@@ -49,7 +49,8 @@
import {VideoCallLayout, videoCallLayout, videoTileCount} from "@app/call/video"
import {makeFeed} from "@app/core/requests"
import {popKey} from "@lib/implicit"
import {checked} from "@app/util/notifications"
import {checked, deferredRoomPath, setChecked} from "@app/util/notifications"
import {makeRoomPath} from "@app/util/routes"
import {pushModal} from "@app/util/modal"
import {pushToast} from "@app/util/toast"
@@ -77,6 +78,21 @@
voiceConnectedHere && $videoCallLayout === VideoCallLayout.Video,
)
const roomPath = makeRoomPath(url, h)
const videoCallChatHidden = $derived(
voiceConnectedHere && $videoCallLayout === VideoCallLayout.Video,
)
$effect(() => {
deferredRoomPath.set(videoCallChatHidden ? roomPath : undefined)
if (voiceConnectedHere && !videoCallChatHidden) {
setChecked(roomPath)
}
})
onDestroy(() => deferredRoomPath.set(undefined))
let prevVideoTileCount = $state(0)
$effect(() => {