feat: Add game activity status (Experimental)
All checks were successful
Queue Release Build / prepare (push) Successful in 21s
Deploy Web Apps / deploy (push) Successful in 5m14s
Queue Release Build / build-windows (push) Successful in 16m18s
Queue Release Build / build-linux (push) Successful in 29m20s
Queue Release Build / finalize (push) Successful in 36s

This commit is contained in:
2026-04-27 05:46:33 +02:00
parent 3858beb28e
commit 66c6f34cd3
52 changed files with 2120 additions and 113 deletions

View File

@@ -4,6 +4,7 @@ import {
inject,
computed,
input,
OnDestroy,
signal
} from '@angular/core';
import { CommonModule } from '@angular/common';
@@ -22,7 +23,8 @@ import {
lucideHash,
lucideUsers,
lucidePlus,
lucideVolumeX
lucideVolumeX,
lucideGamepad2
} from '@ng-icons/lucide';
import { selectOnlineUsers, selectCurrentUser } from '../../../store/users/users.selectors';
import {
@@ -46,6 +48,8 @@ import {
import { VoiceSessionFacade, VoiceWorkspaceService } from '../../../domains/voice-session';
import { DirectMessageService } from '../../../domains/direct-message';
import { VoicePlaybackService } from '../../../domains/voice-connection';
import { formatGameActivityElapsed } from '../../../domains/game-activity';
import { ExternalLinkService } from '../../../core/platform/external-link.service';
import { VoiceControlsComponent } from '../../../domains/voice-session/feature/voice-controls/voice-controls.component';
import { isChannelNameTaken, normalizeChannelName } from '../../../store/rooms/room-channels.rules';
import {
@@ -64,6 +68,7 @@ import {
import {
Channel,
ChatEvent,
GameActivity,
RoomMember,
Room,
User
@@ -98,12 +103,13 @@ type PanelMode = 'channels' | 'users';
lucideHash,
lucideUsers,
lucidePlus,
lucideVolumeX
lucideVolumeX,
lucideGamepad2
})
],
templateUrl: './rooms-side-panel.component.html'
})
export class RoomsSidePanelComponent {
export class RoomsSidePanelComponent implements OnDestroy {
private store = inject(Store);
private router = inject(Router);
private realtime = inject(RealtimeSessionFacade);
@@ -115,9 +121,11 @@ export class RoomsSidePanelComponent {
private voicePlayback = inject(VoicePlaybackService);
private profileCard = inject(ProfileCardService);
private directMessages = inject(DirectMessageService);
private readonly externalLinks = inject(ExternalLinkService);
private readonly voiceActivity = inject(VoiceActivityService);
private readonly voiceConnectivity = inject(VoiceConnectivityHealthService);
private profileCardOpenTimer: ReturnType<typeof setTimeout> | null = null;
private readonly activityTimer = setInterval(() => this.activityNow.set(Date.now()), 1_000);
readonly panelMode = input<PanelMode>('channels');
readonly showVoiceControls = input(true);
@@ -198,6 +206,26 @@ export class RoomsSidePanelComponent {
volumeMenuDisplayName = signal('');
draggedVoiceUserId = signal<string | null>(null);
dragTargetVoiceChannelId = signal<string | null>(null);
activityNow = signal(Date.now());
ngOnDestroy(): void {
clearInterval(this.activityTimer);
this.cancelQueuedProfileCardOpen();
}
gameActivityElapsed(user: User | null | undefined): string {
const activity = user?.gameActivity;
return activity ? formatGameActivityElapsed(activity.startedAt, this.activityNow()) : '';
}
openGameStore(event: Event, activity: GameActivity): void {
event.stopPropagation();
if (activity.store?.url) {
this.externalLinks.open(activity.store.url);
}
}
openProfileCard(event: Event, user: User, editable: boolean): void {
event.stopPropagation();