Logika, która w app.js żyła w zmiennych globalnych, trafia do czterech
composables o wyraźnym zakresie odpowiedzialności:
- useBotStatus jedno połączenie WebSocket na aplikację, z licznikiem
subskrybentów i ponawianiem po zerwaniu. Flaga paused
wstrzymuje aktualizacje na czas przeciągania utworów.
- useToasts kolejka powiadomień wraz z helperem run(), który
opakowuje wywołanie API w parę komunikatów sukces/błąd.
- useTrackProgress płynny pasek postępu - między pakietami z serwera czas
dopisujemy lokalnie, a każdy pakiet resynchronizuje licznik.
- useUploads serwerowa baza plików, współdzielona przez kafelek na
pulpicie i okno z pełną listą.
Dochodzi też utils/plural.ts z polską odmianą liczebników, zamiast
powtarzanego w kilku miejscach warunku count < 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { computed, onUnmounted, ref, watch, type Ref } from 'vue'
|
|
import type { BotStatus } from '@/types/status'
|
|
|
|
const TICK_MS = 100
|
|
|
|
/**
|
|
* Płynny pasek postępu. Backend przysyła `elapsed` raz na sekundę, więc między
|
|
* aktualizacjami dopisujemy czas lokalnie, a każdy pakiet resynchronizuje licznik.
|
|
*/
|
|
export function useTrackProgress(status: Ref<BotStatus | null>) {
|
|
const elapsed = ref(0)
|
|
const duration = ref(0)
|
|
|
|
const timer = window.setInterval(() => {
|
|
if (!status.value?.playing || !status.value.current) return
|
|
elapsed.value = duration.value > 0
|
|
? Math.min(elapsed.value + TICK_MS / 1000, duration.value)
|
|
: elapsed.value + TICK_MS / 1000
|
|
}, TICK_MS)
|
|
|
|
watch(
|
|
() => status.value?.current,
|
|
(current) => {
|
|
duration.value = current?.duration ?? 0
|
|
elapsed.value = current?.elapsed ?? 0
|
|
},
|
|
{ immediate: true, deep: true },
|
|
)
|
|
|
|
onUnmounted(() => window.clearInterval(timer))
|
|
|
|
const percent = computed(() =>
|
|
duration.value > 0 ? Math.min((elapsed.value / duration.value) * 100, 100) : 100,
|
|
)
|
|
|
|
return { elapsed, duration, percent }
|
|
}
|
|
|
|
export function formatTime(seconds: number | null | undefined): string {
|
|
if (seconds === null || seconds === undefined || Number.isNaN(seconds) || seconds < 0) {
|
|
return '0:00'
|
|
}
|
|
const hours = Math.floor(seconds / 3600)
|
|
const minutes = Math.floor((seconds % 3600) / 60)
|
|
const secs = Math.floor(seconds % 60).toString().padStart(2, '0')
|
|
|
|
return hours > 0
|
|
? `${hours}:${minutes.toString().padStart(2, '0')}:${secs}`
|
|
: `${minutes}:${secs}`
|
|
}
|