style: Now uses template files

This commit is contained in:
2026-03-01 14:53:47 +01:00
parent 8c551a90f4
commit d88a476f15
36 changed files with 2089 additions and 2103 deletions

View File

@@ -0,0 +1,205 @@
import { Component, inject, signal, computed, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { Subscription } from 'rxjs';
import {
lucideMic,
lucideMicOff,
lucideMonitor,
lucideMonitorOff,
lucidePhoneOff,
lucideHeadphones,
lucideArrowLeft,
} from '@ng-icons/lucide';
import { WebRTCService } from '../../../core/services/webrtc.service';
import { VoiceSessionService } from '../../../core/services/voice-session.service';
import * as UsersActions from '../../../store/users/users.actions';
import { selectCurrentUser } from '../../../store/users/users.selectors';
@Component({
selector: 'app-floating-voice-controls',
standalone: true,
imports: [CommonModule, NgIcon],
viewProviders: [
provideIcons({
lucideMic,
lucideMonitor,
lucideMonitorOff,
lucidePhoneOff,
lucideHeadphones,
lucideArrowLeft,
}),
],
templateUrl: './floating-voice-controls.component.html'
})
export class FloatingVoiceControlsComponent implements OnInit, OnDestroy {
private webrtcService = inject(WebRTCService);
private voiceSessionService = inject(VoiceSessionService);
private store = inject(Store);
currentUser = this.store.selectSignal(selectCurrentUser);
// Voice state from services
showFloatingControls = this.voiceSessionService.showFloatingControls;
voiceSession = this.voiceSessionService.voiceSession;
isConnected = computed(() => this.webrtcService.isVoiceConnected());
isMuted = signal(false);
isDeafened = signal(false);
isScreenSharing = signal(false);
private stateSubscription: Subscription | null = null;
ngOnInit(): void {
// Sync mute/deafen state from webrtc service
this.isMuted.set(this.webrtcService.isMuted());
this.isDeafened.set(this.webrtcService.isDeafened());
this.isScreenSharing.set(this.webrtcService.isScreenSharing());
}
ngOnDestroy(): void {
this.stateSubscription?.unsubscribe();
}
navigateToServer(): void {
this.voiceSessionService.navigateToVoiceServer();
}
toggleMute(): void {
this.isMuted.update(v => !v);
this.webrtcService.toggleMute(this.isMuted());
// Broadcast mute state change
this.webrtcService.broadcastMessage({
type: 'voice-state',
oderId: this.currentUser()?.oderId || this.currentUser()?.id,
displayName: this.currentUser()?.displayName || 'User',
voiceState: {
isConnected: this.isConnected(),
isMuted: this.isMuted(),
isDeafened: this.isDeafened(),
},
});
}
toggleDeafen(): void {
this.isDeafened.update(v => !v);
this.webrtcService.toggleDeafen(this.isDeafened());
// When deafening, also mute
if (this.isDeafened() && !this.isMuted()) {
this.isMuted.set(true);
this.webrtcService.toggleMute(true);
}
// Broadcast deafen state change
this.webrtcService.broadcastMessage({
type: 'voice-state',
oderId: this.currentUser()?.oderId || this.currentUser()?.id,
displayName: this.currentUser()?.displayName || 'User',
voiceState: {
isConnected: this.isConnected(),
isMuted: this.isMuted(),
isDeafened: this.isDeafened(),
},
});
}
async toggleScreenShare(): Promise<void> {
if (this.isScreenSharing()) {
this.webrtcService.stopScreenShare();
this.isScreenSharing.set(false);
} else {
try {
await this.webrtcService.startScreenShare(false);
this.isScreenSharing.set(true);
} catch (error) {
console.error('Failed to start screen share:', error);
}
}
}
disconnect(): void {
// Stop voice heartbeat
this.webrtcService.stopVoiceHeartbeat();
// Broadcast voice disconnect
this.webrtcService.broadcastMessage({
type: 'voice-state',
oderId: this.currentUser()?.oderId || this.currentUser()?.id,
displayName: this.currentUser()?.displayName || 'User',
voiceState: {
isConnected: false,
isMuted: false,
isDeafened: false,
},
});
// Stop screen sharing if active
if (this.isScreenSharing()) {
this.webrtcService.stopScreenShare();
}
// Disable voice
this.webrtcService.disableVoice();
// Update user voice state in store
const user = this.currentUser();
if (user?.id) {
this.store.dispatch(UsersActions.updateVoiceState({
userId: user.id,
voiceState: { isConnected: false, isMuted: false, isDeafened: false, roomId: undefined, serverId: undefined }
}));
}
// End voice session
this.voiceSessionService.endSession();
// Reset local state
this.isScreenSharing.set(false);
this.isMuted.set(false);
this.isDeafened.set(false);
}
getCompactButtonClass(isActive: boolean): string {
const base = 'w-7 h-7 inline-flex items-center justify-center rounded-lg transition-colors';
if (isActive) {
return base + ' bg-destructive/20 text-destructive hover:bg-destructive/30';
}
return base + ' bg-secondary text-foreground hover:bg-secondary/80';
}
getCompactScreenShareClass(): string {
const base = 'w-7 h-7 inline-flex items-center justify-center rounded-lg transition-colors';
if (this.isScreenSharing()) {
return base + ' bg-primary/20 text-primary hover:bg-primary/30';
}
return base + ' bg-secondary text-foreground hover:bg-secondary/80';
}
getMuteButtonClass(): string {
const base = 'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors';
if (this.isMuted()) {
return base + ' bg-destructive/20 text-destructive hover:bg-destructive/30';
}
return base + ' bg-secondary text-foreground hover:bg-secondary/80';
}
getDeafenButtonClass(): string {
const base = 'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors';
if (this.isDeafened()) {
return base + ' bg-destructive/20 text-destructive hover:bg-destructive/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';
if (this.isScreenSharing()) {
return base + ' bg-primary/20 text-primary hover:bg-primary/30';
}
return base + ' bg-secondary text-foreground hover:bg-secondary/80';
}
}