`@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.
128 lines
3.3 KiB
TypeScript
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();
|
|
}
|
|
}
|