feat: Add emoji and alot of other fixes

This commit is contained in:
2026-06-05 05:40:18 +02:00
parent ca069e2f61
commit 6865147e8f
72 changed files with 3885 additions and 413 deletions

View File

@@ -3,6 +3,7 @@ import {
ElementRef,
HostListener,
OnDestroy,
OnInit,
ViewChild,
computed,
input,
@@ -20,6 +21,11 @@ import {
lucideVolume2,
lucideVolumeX
} from '@ng-icons/lucide';
import {
MEDIA_SEEK_SLIDER_STEPS,
mediaSeekSliderValue,
mediaSeekTimeFromSliderValue
} from './chat-video-player-seek.rules';
@Component({
selector: 'app-chat-video-player',
@@ -40,14 +46,14 @@ import {
styleUrl: './chat-video-player.component.scss'
})
/* eslint-disable @typescript-eslint/member-ordering */
export class ChatVideoPlayerComponent implements OnDestroy {
export class ChatVideoPlayerComponent implements OnInit, OnDestroy {
src = input.required<string>();
filename = input.required<string>();
sizeLabel = input<string>('');
downloadRequested = output<undefined>();
private readonly SINGLE_CLICK_DELAY_MS = 300;
private readonly FULLSCREEN_IDLE_MS = 2200;
private readonly CONTROLS_IDLE_MS = 2200;
@ViewChild('playerRoot') playerRoot?: ElementRef<HTMLDivElement>;
@ViewChild('videoEl') videoRef?: ElementRef<HTMLVideoElement>;
@@ -63,6 +69,8 @@ export class ChatVideoPlayerComponent implements OnDestroy {
private singleClickTimer: ReturnType<typeof setTimeout> | null = null;
private controlsHideTimer: ReturnType<typeof setTimeout> | null = null;
readonly seekSliderSteps = MEDIA_SEEK_SLIDER_STEPS;
progressPercent = computed(() => {
const duration = this.durationSeconds();
@@ -71,16 +79,8 @@ export class ChatVideoPlayerComponent implements OnDestroy {
return (this.currentTimeSeconds() / duration) * 100;
});
seekTrackBackground = computed(() => {
const progress = Math.max(0, Math.min(100, this.progressPercent()));
return this.buildSliderBackground(progress);
});
volumeTrackBackground = computed(() => {
const volume = Math.max(0, Math.min(100, this.isMuted() ? 0 : this.volumePercent()));
return this.buildSliderBackground(volume);
});
seekSliderValue = computed(() => mediaSeekSliderValue(this.currentTimeSeconds(), this.durationSeconds()));
volumeProgressPercent = computed(() => Math.max(0, Math.min(100, this.isMuted() ? 0 : this.volumePercent())));
@HostListener('document:fullscreenchange')
onFullscreenChange(): void {
@@ -89,13 +89,11 @@ export class ChatVideoPlayerComponent implements OnDestroy {
this.isFullscreen.set(isFullscreen);
if (isFullscreen) {
this.revealControlsTemporarily();
return;
}
this.revealControlsTemporarily();
}
this.controlsVisible.set(true);
this.clearControlsHideTimer();
ngOnInit(): void {
this.revealControlsTemporarily();
}
ngOnDestroy(): void {
@@ -104,9 +102,6 @@ export class ChatVideoPlayerComponent implements OnDestroy {
}
onPlayerMouseMove(): void {
if (!this.isFullscreen())
return;
this.revealControlsTemporarily();
}
@@ -184,11 +179,13 @@ export class ChatVideoPlayerComponent implements OnDestroy {
if (!video)
return;
const nextTime = Number((event.target as HTMLInputElement).value);
const sliderValue = Number((event.target as HTMLInputElement).value);
if (!Number.isFinite(nextTime))
if (!Number.isFinite(sliderValue))
return;
const nextTime = mediaSeekTimeFromSliderValue(sliderValue, this.durationSeconds());
video.currentTime = nextTime;
this.currentTimeSeconds.set(nextTime);
this.revealControlsTemporarily();
@@ -272,27 +269,12 @@ export class ChatVideoPlayerComponent implements OnDestroy {
this.revealControlsTemporarily();
}
private buildSliderBackground(fillPercent: number): string {
return [
'linear-gradient(90deg, ',
'hsl(var(--primary)) 0%, ',
`hsl(var(--primary)) ${fillPercent}%, `,
`hsl(var(--secondary)) ${fillPercent}%, `,
'hsl(var(--secondary)) 100%)'
].join('');
}
private revealControlsTemporarily(): void {
if (!this.isFullscreen()) {
this.controlsVisible.set(true);
return;
}
this.controlsVisible.set(true);
this.clearControlsHideTimer();
this.controlsHideTimer = setTimeout(() => {
this.controlsVisible.set(false);
}, this.FULLSCREEN_IDLE_MS);
}, this.CONTROLS_IDLE_MS);
}
private clearControlsHideTimer(): void {