fix: dock app badge shows incorrect number
Closes #122 We now only show number based on open streams
This commit is contained in:
@@ -18,6 +18,7 @@ import { particlePath } from "@/lib/particle-path";
|
||||
import { useParticle } from "@/hooks/use-particle";
|
||||
import type { Particle } from "@/api/types";
|
||||
import { PropsWithChildren, useCallback } from "react";
|
||||
import { useDockBadge } from "@/hooks/use-dock-badge";
|
||||
import { toast } from "sonner";
|
||||
|
||||
function getParticleDisplayName(particle: Particle): string {
|
||||
@@ -170,6 +171,9 @@ function TopBar() {
|
||||
}
|
||||
|
||||
export default function Layout({ children }: PropsWithChildren) {
|
||||
const { networkId } = useParams();
|
||||
useDockBadge(networkId);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen flex-col">
|
||||
<TopBar />
|
||||
|
||||
@@ -8,8 +8,6 @@ import { ComposeOverlay } from "./compose/compose-overlay";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { useStreamParticles } from "@/hooks/use-stream-particles";
|
||||
import { useStreamKeyboardNav } from "@/hooks/use-stream-keyboard-nav";
|
||||
import { useDockBadge } from "@/hooks/use-dock-badge";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
|
||||
/**
|
||||
* Route-level component for /:networkId (index).
|
||||
@@ -21,8 +19,6 @@ export default function NetworkRoot() {
|
||||
const path = particlePath(networkId!, []);
|
||||
|
||||
const { streams, isLoading } = useStreamParticles(path);
|
||||
const userId = useAuthStore((s) => s.user?.id);
|
||||
useDockBadge(streams, userId);
|
||||
const [composeActive, setComposeActive] = useState(false);
|
||||
const [statusTab, setStatusTab] = useState<"open" | "closed">("open");
|
||||
|
||||
|
||||
@@ -1,24 +1,52 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { where } from "firebase/firestore";
|
||||
import { useLiveParticleChildren } from "@/hooks/use-particle";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import { particlePath } from "@/lib/particle-path";
|
||||
import type { Particle, StreamProperties } from "@/api/types";
|
||||
|
||||
type StreamParticle = Particle & { type: "stream"; properties: StreamProperties };
|
||||
|
||||
const openStatusFilter = where("status", "==", "open");
|
||||
|
||||
/**
|
||||
* Syncs the macOS dock badge with the count of unseen streams.
|
||||
* Both last_child_created_at and playback_markers store the child particle's
|
||||
* created_at, so they're directly comparable.
|
||||
* Self-contained hook that syncs the macOS dock badge with the count of
|
||||
* unseen open streams the current user is involved in.
|
||||
*
|
||||
* Sets up its own Firestore listener so it works independently of
|
||||
* whatever stream list is rendered on screen.
|
||||
*/
|
||||
export function useDockBadge(streams: StreamParticle[], userId: string | undefined) {
|
||||
export function useDockBadge(networkId: string | undefined) {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const userId = user?.id;
|
||||
|
||||
const visibilityScopes = useMemo(() => {
|
||||
const scopes: string[] = [];
|
||||
if (userId) scopes.push(`human:${userId}`);
|
||||
if (networkId) scopes.push(`network:${networkId}`);
|
||||
return scopes;
|
||||
}, [userId, networkId]);
|
||||
|
||||
const path = networkId ? particlePath(networkId, []) : undefined;
|
||||
|
||||
const { children } = useLiveParticleChildren(path, {
|
||||
orderByField: "last_child_created_at",
|
||||
orderDirection: "desc",
|
||||
visibilityScopes,
|
||||
whereFilter: openStatusFilter,
|
||||
});
|
||||
|
||||
const unseenCount = useMemo(() => {
|
||||
if (!userId) return 0;
|
||||
return streams.filter((s) => {
|
||||
const lastActivity = s.last_child_created_at?.getTime();
|
||||
return children.filter((c): c is StreamParticle => {
|
||||
if (c.type !== "stream") return false;
|
||||
const lastActivity = c.last_child_created_at?.getTime();
|
||||
if (!lastActivity) return false;
|
||||
const marker = s.playback_markers?.[userId]?.getTime();
|
||||
const marker = c.playback_markers?.[userId]?.getTime();
|
||||
if (marker === undefined) return false;
|
||||
return lastActivity > marker;
|
||||
}).length;
|
||||
}, [streams, userId]);
|
||||
}, [children, userId]);
|
||||
|
||||
useEffect(() => {
|
||||
window.electronApp.setDockBadge(unseenCount);
|
||||
|
||||
@@ -66,7 +66,7 @@ interface UseLiveParticleChildrenParams {
|
||||
}
|
||||
|
||||
export function useLiveParticleChildren(
|
||||
path: ParticlePath,
|
||||
path: ParticlePath | undefined,
|
||||
{
|
||||
orderByField = "created_at",
|
||||
orderDirection = "desc",
|
||||
@@ -81,6 +81,12 @@ export function useLiveParticleChildren(
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!path) {
|
||||
setChildren([]);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
setChildren([]);
|
||||
|
||||
Reference in New Issue
Block a user