/* eslint-disable @typescript-eslint/member-ordering, */ import { Injectable, signal, computed, inject } from '@angular/core'; import { Store } from '@ngrx/store'; import { RoomsActions } from '../../../store/rooms/rooms.actions'; import { buildVoiceSessionRoom, isViewingVoiceSessionServer } from '../domain/voice-session.logic'; import type { VoiceSessionInfo } from '../domain/voice-session.models'; /** * Tracks the user's current voice session across client-side * navigation so that floating voice controls remain visible when * the user is browsing a different server or view. * * This service is purely a UI-state tracker - actual WebRTC * voice management lives in {@link WebRTCService} and its managers. */ @Injectable({ providedIn: 'root' }) export class VoiceSessionFacade { private readonly store = inject(Store); /** Current voice session metadata, or `null` when disconnected. */ private readonly _voiceSession = signal(null); /** Whether the user is currently viewing the voice-connected server. */ private readonly _isViewingVoiceServer = signal(true); /** Reactive read-only voice session. */ readonly voiceSession = computed(() => this._voiceSession()); /** Reactive flag: is the user's current view the voice server? */ readonly isViewingVoiceServer = computed(() => this._isViewingVoiceServer()); /** * Whether the floating voice-controls overlay should be visible. * `true` when a voice session is active AND the user is viewing * a different server. */ readonly showFloatingControls = computed( () => this._voiceSession() !== null && !this._isViewingVoiceServer() ); /** * Begin tracking a voice session. * Called when the user joins a voice channel. * * @param sessionInfo - Metadata describing the voice-connected server/channel. */ startSession(sessionInfo: VoiceSessionInfo): void { this._voiceSession.set(sessionInfo); this._isViewingVoiceServer.set(true); } /** * Stop tracking the voice session. * Called when the user disconnects from voice. */ endSession(): void { this._voiceSession.set(null); this._isViewingVoiceServer.set(true); } /** * Manually flag whether the user is currently viewing the * voice-connected server. * * @param isViewing - `true` if the user's current view is the voice server. */ setViewingVoiceServer(isViewing: boolean): void { this._isViewingVoiceServer.set(isViewing); } /** * Compare the given server ID to the voice session's server and * update the {@link isViewingVoiceServer} flag accordingly. * * @param currentServerId - ID of the server the user is currently viewing. */ checkCurrentRoute(currentServerId: string | null): void { this._isViewingVoiceServer.set( isViewingVoiceSessionServer(this._voiceSession(), currentServerId) ); } /** * Navigate the user back to the voice-connected server by * dispatching a `viewServer` action. */ navigateToVoiceServer(): void { const session = this._voiceSession(); if (!session) return; this.store.dispatch( RoomsActions.viewServer({ room: buildVoiceSessionRoom(session) }) ); this._isViewingVoiceServer.set(true); } /** * Return the server ID of the active voice session, or `null` * if the user is not in a voice channel. */ getVoiceServerId(): string | null { return this._voiceSession()?.serverId ?? null; } }