fix(diagnostics): volume %, auto cast scan, snapshot-on-demand track

- Volume: playerStore.getVolume() already returns 0-100, the extra *100
  was reporting "10000%". Just Math.round() the stored value.
- Cast scan: run automatically the first time the panel is opened so
  the user doesn't have to press the button. Button now doubles as
  "re-scan" while disabled during an in-flight scan. A spinner
  placeholder shows while the initial scan is in progress.
- Track info: capture a single snapshot on open/refresh instead of
  live-subscribing to the player store — live updates were unnecessary
  for a diagnostic dump and slowed the settings page. Use "Refresh"
  to take a fresh snapshot.

cc
This commit is contained in:
vicrodh committed 2026-04-16 11:08:07 -06:00
1 parent d9b1efc091
commit 85057589e6
1 file changed
+25 -18
+25 -18
View File
@@ -1,16 +1,15 @@
<script lang="ts"> <script lang="ts">
import { onMount, onDestroy } from 'svelte'; import { onDestroy } from 'svelte';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { writeText as copyToClipboard } from '@tauri-apps/plugin-clipboard-manager'; import { writeText as copyToClipboard } from '@tauri-apps/plugin-clipboard-manager';
import { t } from '$lib/i18n'; import { t } from '$lib/i18n';
import { RefreshCw, Copy, Check, ChevronDown, ChevronRight, Radio } from 'lucide-svelte'; import { RefreshCw, Copy, Check, ChevronDown, ChevronRight, Radio, LoaderCircle } from 'lucide-svelte';
import { import {
getCurrentTrack, getCurrentTrack,
getIsPlaying, getIsPlaying,
getCurrentTime, getCurrentTime,
getDuration, getDuration,
getVolume, getVolume
subscribe as subscribeToPlayer
} from '$lib/stores/playerStore'; } from '$lib/stores/playerStore';
import type { QconnectConnectionStatus, QconnectSessionSnapshot } from '$lib/services/qconnectRuntime'; import type { QconnectConnectionStatus, QconnectSessionSnapshot } from '$lib/services/qconnectRuntime';
@@ -118,7 +117,6 @@
let qconnectOpen = $state(true); let qconnectOpen = $state(true);
let castOpen = $state(true); let castOpen = $state(true);
let playerUnsubscribe: (() => void) | null = null;
const CAST_SCAN_DURATION_MS = 10000; const CAST_SCAN_DURATION_MS = 10000;
// Redact things that look like UUIDs / hex IDs / tokens (defensive: keep paste // Redact things that look like UUIDs / hex IDs / tokens (defensive: keep paste
@@ -135,7 +133,7 @@
const track = getCurrentTrack(); const track = getCurrentTrack();
return { return {
isPlaying: getIsPlaying(), isPlaying: getIsPlaying(),
volumePercent: Math.round(getVolume() * 100), volumePercent: Math.round(getVolume()),
positionSecs: Math.round(getCurrentTime()), positionSecs: Math.round(getCurrentTime()),
durationSecs: Math.round(getDuration()), durationSecs: Math.round(getDuration()),
hasTrack: !!track, hasTrack: !!track,
@@ -359,23 +357,17 @@
panelOpen = !panelOpen; panelOpen = !panelOpen;
if (panelOpen) { if (panelOpen) {
if (!diagnostics) loadDiagnostics(); if (!diagnostics) loadDiagnostics();
// Keep playback snapshot refreshed while the panel is open. // Auto-run a cast scan the first time the panel is opened. Don't
if (!playerUnsubscribe) { // block the diagnostics load on it — scan runs concurrently and
playerUnsubscribe = subscribeToPlayer(() => { // fills its own section when done.
playback = snapshotPlayback(); if (!castScan && !castScanning) {
}); void runCastScan();
} }
} else if (playerUnsubscribe) {
playerUnsubscribe();
playerUnsubscribe = null;
} }
} }
onDestroy(() => { onDestroy(() => {
if (playerUnsubscribe) { // (intentional) don't leave any subscriptions behind
playerUnsubscribe();
playerUnsubscribe = null;
}
}); });
function playbackRows(p: PlaybackSnapshot): DiagRow[] { function playbackRows(p: PlaybackSnapshot): DiagRow[] {
@@ -528,6 +520,12 @@
: $t('settings.developer.diagnostics.castScan')} : $t('settings.developer.diagnostics.castScan')}
</button> </button>
</div> </div>
{#if castScanning && !castScan}
<div class="cast-scan-placeholder">
<LoaderCircle size={20} class="spinning" />
<span>{$t('settings.developer.diagnostics.castScanning')}</span>
</div>
{/if}
{#if castScan} {#if castScan}
<table class="diag-table"> <table class="diag-table">
<thead> <thead>
@@ -773,6 +771,15 @@
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
} }
.cast-scan-placeholder {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
color: var(--text-muted);
font-size: 12px;
}
@keyframes spin { @keyframes spin {
from { transform: rotate(0deg); } from { transform: rotate(0deg); }
to { transform: rotate(360deg); } to { transform: rotate(360deg); }