android: hours on the library's count line, By format, Jump back in on the empty search
The desktop Library summary's hours on the phone's count line; a By format order from the file stats (lossless by depth and rate first, then by bitrate, the badge as the card's line); the empty Search page's Jump back in — the last records played — as the desktop's empty search shows them.
This commit is contained in:
1 parent
b50577fc81
commit
f8c3b90665
6 files changed
+39
-8
No files matched your search
@@ -21,7 +21,7 @@
|
||||
import { note } from "./notice.svelte.js";
|
||||
import { fmtOf, albumFmt, fmtBytes, basename, dirname, longDur, mmss, titleFromName } from "./util.js";
|
||||
|
||||
const SORTS = [["added", "Recently added"], ["az", "A–Z"], ["artist", "By artist"], ["year", "By year"]];
|
||||
const SORTS = [["added", "Recently added"], ["az", "A–Z"], ["artist", "By artist"], ["year", "By year"], ["format", "By format"]];
|
||||
|
||||
/* the last sheet is kept through its slide down */
|
||||
let shown = $state(null);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
let { entry, screenEl = null } = $props();
|
||||
|
||||
const TABS = [["albums", "Albums"], ["artists", "Artists"], ["tracks", "Tracks"], ["playlists", "Playlists"], ["gaps", "Gaps"]];
|
||||
const SORTS = [["added", "Recently added"], ["az", "A–Z"], ["artist", "By artist"], ["year", "By year"]];
|
||||
const SORTS = [["added", "Recently added"], ["az", "A–Z"], ["artist", "By artist"], ["year", "By year"], ["format", "By format"]];
|
||||
|
||||
const tab = $derived(entry.c.tab || "albums");
|
||||
const sort = $derived(entry.c.sort || "added");
|
||||
@@ -30,11 +30,25 @@
|
||||
if (sort === "az") return x.title.localeCompare(y.title);
|
||||
if (sort === "artist") return x.artist.localeCompare(y.artist) || (x.year || 0) - (y.year || 0);
|
||||
if (sort === "year") return (y.year || 0) - (x.year || 0) || y.added_at - x.added_at;
|
||||
if (sort === "format") {
|
||||
/* lossless first, then the higher bitrate, then the name */
|
||||
const fx = fmtRank(lib.stats[x.id]);
|
||||
const fy = fmtRank(lib.stats[y.id]);
|
||||
return fy - fx || x.title.localeCompare(y.title);
|
||||
}
|
||||
return y.added_at - x.added_at;
|
||||
});
|
||||
return l;
|
||||
});
|
||||
const totalTracks = $derived(lib.albums.reduce((n, a) => n + (a.track_count || 0), 0));
|
||||
const totalSecs = $derived(Object.values(lib.stats).reduce((n, st) => n + (st.secs || 0), 0));
|
||||
const hours = $derived(totalSecs >= 3600 ? Math.round(totalSecs / 3600) + " hours" : totalSecs ? Math.round(totalSecs / 60) + " min" : "");
|
||||
/* By format: a number the sort can compare — lossless by depth and rate, lossy by bitrate */
|
||||
function fmtRank(st) {
|
||||
if (!st || !st.formats?.length) return 0;
|
||||
if (st.bit_depth && st.sample_rate) return 1_000_000 + st.bit_depth * 1000 + Math.round(st.sample_rate / 1000);
|
||||
return st.avg_kbps || 1;
|
||||
}
|
||||
const arts = $derived(artists());
|
||||
|
||||
/* ── Gaps — the desktop's (Library.svelte's gapSection): only a shelf
|
||||
@@ -101,7 +115,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
<div class="countline">
|
||||
<span class="t-sub">{list.length} album{list.length === 1 ? "" : "s"} · {totalTracks} tracks</span>
|
||||
<span class="t-sub">{list.length} album{list.length === 1 ? "" : "s"} · {totalTracks} tracks{hours ? " · " + hours : ""}</span>
|
||||
<button class="iconbtn sm muted" onclick={() => patch({ view: view === "grid" ? "list" : "grid" })} aria-label="Grid or list">
|
||||
<Icon name={view === "grid" ? "playlist" : "layers"} size={18} />
|
||||
</button>
|
||||
@@ -111,7 +125,7 @@
|
||||
{:else if view === "grid"}
|
||||
<div class="grid2">
|
||||
{#each list as a (a.id)}
|
||||
<Release title={a.title} sub={sort === "year" ? String(a.year || "") : a.artist} path={a.art_path} badge={statLabel(lib.stats[a.id]) || null} onclick={() => push("album", { id: a.id }, screenEl)} onmore={() => openHalf("album", { album: a })} />
|
||||
<Release title={a.title} sub={sort === "year" ? String(a.year || "") : sort === "format" ? (statLabel(lib.stats[a.id]) || a.artist) : a.artist} path={a.art_path} badge={statLabel(lib.stats[a.id]) || null} onclick={() => push("album", { id: a.id }, screenEl)} onmore={() => openHalf("album", { album: a })} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -292,6 +292,14 @@
|
||||
Artists, records and songs from the catalog; a song plays from the best copy the network has, a record opens its page.
|
||||
{#if !online}Sign in on Community to play what the library does not hold.{/if}
|
||||
</div>
|
||||
{#if lib.recents.length}
|
||||
<div class="sec"><h2>Jump back in <em>· picks up where you left off</em></h2></div>
|
||||
<div class="rail">
|
||||
{#each lib.recents.slice(0, 8) as r (r.album_id)}
|
||||
<Release title={r.title} sub={r.artist} path={r.art_path} onclick={() => push("album", { id: r.album_id }, screenEl)} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if recents.length}
|
||||
<div class="sec"><h2>Recent</h2><button class="all" onclick={() => { recents = []; keepRecents(); }}>Clear</button></div>
|
||||
<div class="chips recent-chips" style="padding-bottom: 12px">
|
||||
|
||||
Reference in new issue
Block a user