import { useEffect, useRef } from 'react'; import { useVoiceStore } from '../../stores/voiceStore'; import { useSpaceStore } from '../../stores/spaceStore'; import { isAndroidApp, onAndroidHangup, startAndroidVoiceService, stopAndroidVoiceService, } from '../../platform/androidVoice'; /** * Liga e desliga o servico de primeiro plano do Android conforme a chamada * comeca e termina. Nao renderiza nada; fora do APK nao faz nada. * * Assina a store direto, sem seletor de re-render: o efeito colateral e uma * chamada ao nativo, e uma re-renderizacao por mudanca de estado da voz seria * so custo. */ export function AndroidVoiceService() { const wasConnected = useRef(useVoiceStore.getState().isLiveKitConnected); useEffect(() => { if (!isAndroidApp()) return; const channelLabel = (channelId: string | null): string | undefined => { if (!channelId) return undefined; if (channelId.startsWith('dm-')) return 'Chamada'; return useSpaceStore.getState().channels.find((c) => c.id === channelId)?.name; }; // Entrar na call e o gatilho, mas a montagem pode acontecer com uma // chamada ja em andamento — uma recarga da WebView, por exemplo. Nesse caso // o servico precisa subir agora, nao na proxima transicao. const initial = useVoiceStore.getState(); if (initial.isLiveKitConnected) { startAndroidVoiceService(channelLabel(initial.currentVoiceChannelId)); } const unsubscribe = useVoiceStore.subscribe((state) => { const connected = state.isLiveKitConnected; if (connected === wasConnected.current) return; wasConnected.current = connected; if (connected) startAndroidVoiceService(channelLabel(state.currentVoiceChannelId)); else stopAndroidVoiceService(); }); const removeHangup = onAndroidHangup(() => { // A notificacao so pede para sair; quem sabe encerrar a sessao do LiveKit // e o app web. O servico para quando a store refletir a saida, pelo // mesmo caminho de quando se sai pela interface. const { disconnectFn, leaveVoice } = useVoiceStore.getState(); if (disconnectFn) void disconnectFn(); else leaveVoice(); }); return () => { unsubscribe(); removeHangup(); // Desmontar nao significa sair da call (a arvore de componentes pode // remontar), mas deixar o servico ligado sem ninguem para desliga-lo // seria pior: uma notificacao permanente que so some matando o app. if (!useVoiceStore.getState().isLiveKitConnected) stopAndroidVoiceService(); }; }, []); return null; }