fix: restore build and stabilize E2E cross-signal behavior
Revert the automated member-ordering pass that broke Angular field init (TS2729) and disable that rule until a safe reorder strategy exists. Fix modal/confirm dialog i18n defaults via template fallbacks, search all active endpoints (including offline), register foreign rooms with actor owner IDs, sync profile display names from avatar summaries, and guard dm-chat when a private call converts to a group conversation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/member-ordering, complexity */
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
@@ -87,42 +88,55 @@ import { APP_TRANSLATE_IMPORTS, AppI18nService } from '../../../core/i18n';
|
||||
}
|
||||
})
|
||||
export class VoiceWorkspaceComponent {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
|
||||
private readonly store = inject(Store);
|
||||
private readonly webrtc = inject(VoiceConnectionFacade);
|
||||
private readonly screenShare = inject(ScreenShareFacade);
|
||||
private readonly viewport = inject(ViewportService);
|
||||
readonly isMobile = this.viewport.isMobile;
|
||||
private readonly voicePlayback = inject(VoicePlaybackService);
|
||||
private readonly workspacePlayback = inject(VoiceWorkspacePlaybackService);
|
||||
private readonly voiceSession = inject(VoiceSessionFacade);
|
||||
private readonly voiceWorkspace = inject(VoiceWorkspaceService);
|
||||
private readonly appI18n = inject(AppI18nService);
|
||||
|
||||
private readonly remoteStreamRevision = signal(0);
|
||||
|
||||
private readonly miniWindowWidth = 320;
|
||||
private readonly miniWindowHeight = 228;
|
||||
private miniWindowDragging = false;
|
||||
private miniDragOffsetX = 0;
|
||||
private miniDragOffsetY = 0;
|
||||
private wasExpanded = false;
|
||||
private wasAutoHideChrome = false;
|
||||
private headerHideTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
private readonly observedRemoteStreams = new Map<string, {
|
||||
stream: MediaStream;
|
||||
cleanup: () => void;
|
||||
}>();
|
||||
|
||||
readonly miniPreviewRef = viewChild<ElementRef<HTMLVideoElement>>('miniPreview');
|
||||
|
||||
readonly currentRoom = this.store.selectSignal(selectCurrentRoom);
|
||||
|
||||
readonly currentUser = this.store.selectSignal(selectCurrentUser);
|
||||
|
||||
readonly onlineUsers = this.store.selectSignal(selectOnlineUsers);
|
||||
|
||||
readonly voiceSessionInfo = this.voiceSession.voiceSession;
|
||||
|
||||
readonly showExpanded = this.voiceWorkspace.isExpanded;
|
||||
|
||||
readonly showMiniWindow = this.voiceWorkspace.isMinimized;
|
||||
|
||||
readonly shouldConnectRemoteShares = this.voiceWorkspace.shouldConnectRemoteShares;
|
||||
|
||||
readonly miniPosition = this.voiceWorkspace.miniWindowPosition;
|
||||
|
||||
readonly showWorkspaceHeader = signal(true);
|
||||
|
||||
readonly isConnected = computed(() => this.webrtc.isVoiceConnected());
|
||||
|
||||
readonly isMuted = computed(() => this.webrtc.isMuted());
|
||||
|
||||
readonly isDeafened = computed(() => this.webrtc.isDeafened());
|
||||
|
||||
readonly isScreenSharing = computed(() => this.screenShare.isScreenSharing());
|
||||
|
||||
readonly includeSystemAudio = signal(false);
|
||||
|
||||
readonly screenShareQuality = signal<ScreenShareQuality>('balanced');
|
||||
|
||||
readonly askScreenShareQuality = signal(true);
|
||||
|
||||
readonly showScreenShareQualityDialog = signal(false);
|
||||
|
||||
readonly connectedVoiceUsers = computed(() => {
|
||||
@@ -276,23 +290,18 @@ export class VoiceWorkspaceComponent {
|
||||
});
|
||||
|
||||
readonly isWidescreenMode = computed(() => this.widescreenShareId() !== null);
|
||||
|
||||
readonly shouldAutoHideChrome = computed(
|
||||
() => this.showExpanded() && this.isWidescreenMode() && this.activeShares().length > 0
|
||||
);
|
||||
|
||||
readonly hasMultipleShares = computed(() => this.activeShares().length > 1);
|
||||
|
||||
readonly widescreenShare = computed(
|
||||
() => this.activeShares().find((share) => share.id === this.widescreenShareId()) ?? null
|
||||
);
|
||||
|
||||
readonly focusedAudioShare = computed(() => {
|
||||
const share = this.widescreenShare();
|
||||
|
||||
return share && !share.isLocal && share.hasAudio ? share : null;
|
||||
});
|
||||
|
||||
readonly focusedShareTitle = computed(() => {
|
||||
const share = this.widescreenShare();
|
||||
|
||||
@@ -308,7 +317,6 @@ export class VoiceWorkspaceComponent {
|
||||
? this.appI18n.instant('voice.workspace.yourCamera')
|
||||
: this.appI18n.instant('voice.workspace.yourScreen');
|
||||
});
|
||||
|
||||
readonly thumbnailShares = computed(() => {
|
||||
const widescreenShareId = this.widescreenShareId();
|
||||
|
||||
@@ -318,11 +326,9 @@ export class VoiceWorkspaceComponent {
|
||||
|
||||
return this.activeShares().filter((share) => share.id !== widescreenShareId);
|
||||
});
|
||||
|
||||
readonly miniPreviewShare = computed(
|
||||
() => this.widescreenShare() ?? this.activeShares()[0] ?? null
|
||||
);
|
||||
|
||||
readonly miniPreviewTitle = computed(() => {
|
||||
const previewShare = this.miniPreviewShare();
|
||||
|
||||
@@ -338,9 +344,7 @@ export class VoiceWorkspaceComponent {
|
||||
? this.appI18n.instant('voice.workspace.yourCamera')
|
||||
: this.appI18n.instant('voice.workspace.yourScreen');
|
||||
});
|
||||
|
||||
readonly liveShareCount = computed(() => this.activeShares().length);
|
||||
|
||||
readonly connectedVoiceChannelName = computed(() => {
|
||||
const me = this.currentUser();
|
||||
const room = this.currentRoom();
|
||||
@@ -357,55 +361,21 @@ export class VoiceWorkspaceComponent {
|
||||
|
||||
return sessionRoomName || this.appI18n.instant('voice.workspace.voiceLounge');
|
||||
});
|
||||
|
||||
readonly serverName = computed(
|
||||
() => this.currentRoom()?.name || this.voiceSessionInfo()?.serverName || this.appI18n.instant('voice.workspace.voiceServer')
|
||||
);
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
liveStreamCountLabel(count: number): string {
|
||||
const key = count === 1 ? 'voice.workspace.liveStream' : 'voice.workspace.liveStreams';
|
||||
|
||||
private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
|
||||
return this.appI18n.instant(key, { count });
|
||||
}
|
||||
|
||||
private readonly store = inject(Store);
|
||||
miniWindowStreamHint(count: number): string {
|
||||
const key = count === 1 ? 'voice.workspace.miniWindowHintSingle' : 'voice.workspace.miniWindowHint';
|
||||
|
||||
private readonly webrtc = inject(VoiceConnectionFacade);
|
||||
|
||||
private readonly screenShare = inject(ScreenShareFacade);
|
||||
|
||||
private readonly viewport = inject(ViewportService);
|
||||
|
||||
private readonly voicePlayback = inject(VoicePlaybackService);
|
||||
|
||||
private readonly workspacePlayback = inject(VoiceWorkspacePlaybackService);
|
||||
|
||||
private readonly voiceSession = inject(VoiceSessionFacade);
|
||||
|
||||
private readonly voiceWorkspace = inject(VoiceWorkspaceService);
|
||||
|
||||
private readonly appI18n = inject(AppI18nService);
|
||||
|
||||
private readonly remoteStreamRevision = signal(0);
|
||||
|
||||
private readonly miniWindowWidth = 320;
|
||||
|
||||
private readonly miniWindowHeight = 228;
|
||||
|
||||
private miniWindowDragging = false;
|
||||
|
||||
private miniDragOffsetX = 0;
|
||||
|
||||
private miniDragOffsetY = 0;
|
||||
|
||||
private wasExpanded = false;
|
||||
|
||||
private wasAutoHideChrome = false;
|
||||
|
||||
private headerHideTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
private readonly observedRemoteStreams = new Map<string, {
|
||||
stream: MediaStream;
|
||||
cleanup: () => void;
|
||||
}>();
|
||||
return this.appI18n.instant(key, { count });
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.destroyRef.onDestroy(() => {
|
||||
@@ -539,6 +509,14 @@ export class VoiceWorkspaceComponent {
|
||||
});
|
||||
}
|
||||
|
||||
onWorkspacePointerMove(): void {
|
||||
if (!this.shouldAutoHideChrome()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revealWorkspaceChrome();
|
||||
}
|
||||
|
||||
@HostListener('window:mousemove', ['$event'])
|
||||
onWindowMouseMove(event: MouseEvent): void {
|
||||
if (!this.miniWindowDragging) {
|
||||
@@ -570,26 +548,6 @@ export class VoiceWorkspaceComponent {
|
||||
this.ensureMiniWindowPosition();
|
||||
}
|
||||
|
||||
liveStreamCountLabel(count: number): string {
|
||||
const key = count === 1 ? 'voice.workspace.liveStream' : 'voice.workspace.liveStreams';
|
||||
|
||||
return this.appI18n.instant(key, { count });
|
||||
}
|
||||
|
||||
miniWindowStreamHint(count: number): string {
|
||||
const key = count === 1 ? 'voice.workspace.miniWindowHintSingle' : 'voice.workspace.miniWindowHint';
|
||||
|
||||
return this.appI18n.instant(key, { count });
|
||||
}
|
||||
|
||||
onWorkspacePointerMove(): void {
|
||||
if (!this.shouldAutoHideChrome()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revealWorkspaceChrome();
|
||||
}
|
||||
|
||||
trackUser(index: number, user: User): string {
|
||||
return this.getUserPeerKey(user) || `${index}`;
|
||||
}
|
||||
@@ -1099,5 +1057,4 @@ export class VoiceWorkspaceComponent {
|
||||
private clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user