Files
Toju/toju-app/src/app/domains/voice-session/application/services/voice-workspace.service.ts
T
myxelium d71e3a98da style: drop obsolete member-ordering eslint disables
`@typescript-eslint/member-ordering` is off repo-wide because bulk member
reordering breaks Angular inject()/field init order, so the per-file disables
are dead weight. Removing them left a blank first line, stripped here too.
2026-08-14 03:19:29 +02:00

128 lines
3.3 KiB
TypeScript

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<VoiceWorkspaceMode>('hidden');
private readonly _focusedStreamId = signal<string | null>(null);
private readonly _connectRemoteShares = signal(false);
private readonly _miniWindowPosition = signal<VoiceWorkspacePosition>(
DEFAULT_MINI_WINDOW_POSITION
);
private readonly _hasCustomMiniWindowPosition = signal(false);
readonly mode = computed<VoiceWorkspaceMode>(() => {
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();
}
}