import { Injectable, computed, effect, inject, signal } from '@angular/core'; import { VoiceSessionFacade } from '../facades/voice-session.facade'; export type VoiceWorkspaceMode = 'hidden' | 'expanded' | 'minimized'; export interface VoiceWorkspacePosition { left: number; top: number; } const DEFAULT_MINI_WINDOW_POSITION: VoiceWorkspacePosition = { left: 24, top: 24 }; @Injectable({ providedIn: 'root' }) export class VoiceWorkspaceService { private readonly voiceSession = inject(VoiceSessionFacade); private readonly _mode = signal('hidden'); private readonly _focusedStreamId = signal(null); private readonly _connectRemoteShares = signal(false); private readonly _miniWindowPosition = signal( DEFAULT_MINI_WINDOW_POSITION ); private readonly _hasCustomMiniWindowPosition = signal(false); readonly mode = computed(() => { if (!this.voiceSession.voiceSession() || !this.voiceSession.isViewingVoiceServer()) { return 'hidden'; } return this._mode(); }); readonly isExpanded = computed(() => this.mode() === 'expanded'); readonly isMinimized = computed(() => this.mode() === 'minimized'); readonly isVisible = computed(() => this.mode() !== 'hidden'); readonly focusedStreamId = computed(() => this._focusedStreamId()); readonly shouldConnectRemoteShares = computed( () => this.isVisible() && this._connectRemoteShares() ); readonly miniWindowPosition = computed(() => this._miniWindowPosition()); readonly hasCustomMiniWindowPosition = computed(() => this._hasCustomMiniWindowPosition()); constructor() { effect(() => { if (this.voiceSession.voiceSession()) { return; } this.reset(); }); } open( focusedStreamId: string | null = null, options?: { connectRemoteShares?: boolean } ): void { if (!this.voiceSession.voiceSession()) { return; } if (options && Object.prototype.hasOwnProperty.call(options, 'connectRemoteShares')) { this._connectRemoteShares.set(options.connectRemoteShares === true); } this._focusedStreamId.set(focusedStreamId); this._mode.set('expanded'); } focusStream(streamId: string, options?: { connectRemoteShares?: boolean }): void { this.open(streamId, options); } minimize(): void { if (!this.voiceSession.voiceSession()) { return; } this._mode.set('minimized'); } restore(): void { this.open(this._focusedStreamId()); } close(): void { this._mode.set('hidden'); this._connectRemoteShares.set(false); } showChat(): void { if (this._mode() === 'expanded') { this._mode.set('hidden'); this._connectRemoteShares.set(false); } } clearFocusedStream(): void { this._focusedStreamId.set(null); } setMiniWindowPosition(position: VoiceWorkspacePosition, markCustom = true): void { this._miniWindowPosition.set(position); this._hasCustomMiniWindowPosition.set(markCustom); } resetMiniWindowPosition(): void { this._miniWindowPosition.set(DEFAULT_MINI_WINDOW_POSITION); this._hasCustomMiniWindowPosition.set(false); } reset(): void { this._mode.set('hidden'); this._focusedStreamId.set(null); this._connectRemoteShares.set(false); this.resetMiniWindowPosition(); } }