feat: add download management section in Settings

- Download stats display (tracks count, size used)
- Storage limit dropdown (500MB to Unlimited)
- Clear downloads button
- Open folder button (sneaky feature)
This commit is contained in:
vicrodh committed 2026-01-09 19:44:02 -06:00
1 parent 7149cf5c4b
commit 20c34caed0
1 file changed
+145 -3
+145 -3
View File
@@ -1,11 +1,18 @@
<script lang="ts">
import { onMount } from 'svelte';
import { invoke } from '@tauri-apps/api/core';
import { ArrowLeft } from 'lucide-svelte';
import { ArrowLeft, FolderOpen } from 'lucide-svelte';
import Toggle from '../Toggle.svelte';
import Dropdown from '../Dropdown.svelte';
import VolumeSlider from '../VolumeSlider.svelte';
import Tooltip from '../Tooltip.svelte';
import {
getDownloadCacheStats,
clearDownloadCache,
openDownloadCacheFolder,
setDownloadCacheLimit,
type DownloadCacheStats
} from '$lib/stores/downloadState';
interface Props {
onBack?: () => void;
@@ -29,10 +36,15 @@
let { onBack, onLogout, userName = 'User', userEmail = '', subscription = 'Qobuz' }: Props = $props();
// Cache state
// Cache state (memory cache)
let cacheStats = $state<CacheStats | null>(null);
let isClearing = $state(false);
// Download cache state (offline storage)
let downloadStats = $state<DownloadCacheStats | null>(null);
let isClearingDownloads = $state(false);
let downloadCacheLimit = $state('2 GB'); // Default 2GB
// Audio device state
let audioDevices = $state<AudioDevice[]>([]);
let audioDeviceOptions = $derived(['System Default', ...audioDevices.map(d => d.name)]);
@@ -108,6 +120,9 @@
// Load cache stats
loadCacheStats();
// Load download cache stats
loadDownloadStats();
// Load audio devices
loadAudioDevices();
@@ -279,6 +294,68 @@
}
}
async function loadDownloadStats() {
try {
downloadStats = await getDownloadCacheStats();
// Set the limit dropdown to match current limit
if (downloadStats.limitBytes) {
const limitGb = downloadStats.limitBytes / (1024 * 1024 * 1024);
if (limitGb <= 0.5) downloadCacheLimit = '500 MB';
else if (limitGb <= 1) downloadCacheLimit = '1 GB';
else if (limitGb <= 2) downloadCacheLimit = '2 GB';
else if (limitGb <= 5) downloadCacheLimit = '5 GB';
else if (limitGb <= 10) downloadCacheLimit = '10 GB';
else downloadCacheLimit = 'Unlimited';
} else {
downloadCacheLimit = 'Unlimited';
}
} catch (err) {
console.error('Failed to load download stats:', err);
}
}
async function handleClearDownloads() {
if (isClearingDownloads) return;
isClearingDownloads = true;
try {
await clearDownloadCache();
await loadDownloadStats();
} catch (err) {
console.error('Failed to clear download cache:', err);
} finally {
isClearingDownloads = false;
}
}
async function handleOpenDownloadFolder() {
try {
await openDownloadCacheFolder();
} catch (err) {
console.error('Failed to open download folder:', err);
}
}
async function handleDownloadLimitChange(limit: string) {
downloadCacheLimit = limit;
let limitMb: number | null = null;
switch (limit) {
case '500 MB': limitMb = 500; break;
case '1 GB': limitMb = 1024; break;
case '2 GB': limitMb = 2048; break;
case '5 GB': limitMb = 5120; break;
case '10 GB': limitMb = 10240; break;
case 'Unlimited': limitMb = null; break;
}
try {
await setDownloadCacheLimit(limitMb);
await loadDownloadStats();
} catch (err) {
console.error('Failed to set download limit:', err);
}
}
async function handleClearCache() {
if (isClearing) return;
isClearing = true;
@@ -523,7 +600,7 @@
{/if}
</section>
<!-- Storage Section -->
<!-- Storage Section (Memory Cache) -->
<section class="section">
<h3 class="section-title">Storage</h3>
<div class="setting-row">
@@ -557,6 +634,50 @@
</button>
</div>
</section>
<!-- Downloads Section (Offline Storage) -->
<section class="section">
<h3 class="section-title">Downloads</h3>
<div class="setting-row">
<span class="setting-label">Downloaded Tracks</span>
<span class="setting-value">
{#if downloadStats}
{downloadStats.readyTracks} tracks ({formatBytes(downloadStats.totalSizeBytes)})
{:else}
Loading...
{/if}
</span>
</div>
<div class="setting-row">
<span class="setting-label">Storage Limit</span>
<Dropdown
value={downloadCacheLimit}
options={['500 MB', '1 GB', '2 GB', '5 GB', '10 GB', 'Unlimited']}
onchange={handleDownloadLimitChange}
/>
</div>
<div class="setting-row">
<span class="setting-label">Clear Downloads</span>
<button
class="clear-btn"
onclick={handleClearDownloads}
disabled={isClearingDownloads || !downloadStats || downloadStats.readyTracks === 0}
>
{isClearingDownloads ? 'Clearing...' : 'Clear All'}
</button>
</div>
<div class="setting-row last">
<span class="setting-label">Open Folder</span>
<button
class="folder-btn"
onclick={handleOpenDownloadFolder}
title="Open download cache folder"
>
<FolderOpen size={16} />
<span>Open</span>
</button>
</div>
</section>
</div>
<style>
@@ -741,6 +862,27 @@
cursor: not-allowed;
}
.folder-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border-radius: 8px;
border: 1px solid var(--text-muted);
background: none;
color: var(--text-secondary);
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
}
.folder-btn:hover {
border-color: var(--text-primary);
color: var(--text-primary);
background-color: var(--bg-hover);
}
/* Last.fm styles */
.lastfm-connected {
display: flex;