feat: Add webcam basic support

This commit is contained in:
2026-03-30 03:10:44 +02:00
parent 727059fb52
commit b7d4bf20e3
40 changed files with 1042 additions and 296 deletions

View File

@@ -86,6 +86,25 @@
/>
</button>
<!-- Camera Toggle -->
<button
type="button"
(click)="toggleCamera()"
[class]="getCameraButtonClass()"
>
@if (isCameraEnabled()) {
<ng-icon
name="lucideVideoOff"
class="w-5 h-5"
/>
} @else {
<ng-icon
name="lucideVideo"
class="w-5 h-5"
/>
}
</button>
<!-- Screen Share Toggle -->
<button
type="button"

View File

@@ -84,6 +84,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
connectionErrorMessage = computed(() => this.webrtcService.connectionErrorMessage());
isMuted = signal(false);
isDeafened = signal(false);
isCameraEnabled = computed(() => this.webrtcService.isCameraEnabled());
isScreenSharing = this.screenShareService.isScreenSharing;
showSettings = signal(false);
@@ -281,6 +282,12 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
})
);
this.store.dispatch(
UsersActions.updateCameraState({
userId: user.id,
cameraState: { isEnabled: false }
})
);
}
// End voice session for floating controls
@@ -364,6 +371,42 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
}
async toggleCamera(): Promise<void> {
if (!this.isConnected()) {
return;
}
const user = this.currentUser();
if (this.isCameraEnabled()) {
this.webrtcService.disableCamera();
if (user?.id) {
this.store.dispatch(
UsersActions.updateCameraState({
userId: user.id,
cameraState: { isEnabled: false }
})
);
}
return;
}
try {
await this.webrtcService.enableCamera();
if (user?.id) {
this.store.dispatch(
UsersActions.updateCameraState({
userId: user.id,
cameraState: { isEnabled: true }
})
);
}
} catch (_error) {}
}
async toggleScreenShare(): Promise<void> {
if (this.isScreenSharing()) {
this.screenShareService.stopScreenShare();
@@ -562,6 +605,17 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
return `${base} bg-secondary text-foreground hover:bg-secondary/80`;
}
getCameraButtonClass(): string {
const base =
'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
if (this.isCameraEnabled()) {
return `${base} bg-primary/20 text-primary hover:bg-primary/30`;
}
return `${base} bg-secondary text-foreground hover:bg-secondary/80`;
}
getScreenShareButtonClass(): string {
const base =
'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';