import { useEffect } from 'react'; import { useAtomValue } from 'jotai'; import { callEmbedAtom } from '../state/callEmbed'; import { useCallControlState } from '../plugins/call'; import { invokeTauri, useTauriEvent } from './useTauri'; type ThumbbarAction = { action: 'mute' | 'deafen' | 'end' }; /** * P5-44 — Taskbar thumbnail toolbar (call controls). While a call is active, * mirrors the mic/sound state onto the native `set_thumbbar` command (three * Mute / Deafen / End-Call buttons on the Windows taskbar thumbnail toolbar) and * hides them when the call ends. Thumb-button clicks come back as the * `thumbbar-action` event and drive the real call controls. No-op in the browser. */ export function useTauriThumbbar(): void { const callEmbed = useAtomValue(callEmbedAtom); const { microphone, sound } = useCallControlState(callEmbed?.control); const active = callEmbed !== undefined; // Muted / deafened only make sense while a call is active; report false // otherwise so the buttons render in a sane (hidden) state. const muted = active && !microphone; const deafened = active && !sound; useEffect(() => { invokeTauri('set_thumbbar', { active, muted, deafened }); }, [active, muted, deafened]); useTauriEvent('thumbbar-action', ({ action }) => { if (!callEmbed) return; if (action === 'mute') { // toggleMicrophone flips the mic; `microphone === false` means muted. callEmbed.control.toggleMicrophone(); } else if (action === 'deafen') { // toggleSound flips local audio; `sound === false` means deafened. It also // mutes the mic while deafened, matching the in-app Deafen control. callEmbed.control.toggleSound(); } else if (action === 'end') { callEmbed.hangup(); } }); }