Merge branch 'master' into worktree-mosaic-library
Renumbers the mosaic's requirement IDs out of the way of the download work that landed on master in parallel: it had already claimed DR-163/DR-164 and UT-162, so the mosaic layout is now DR-172, the library favourites scope DR-173, and its composition test UT-167. Note for the download branch: its UT-162..UT-165 rows trace to DR-163..DR-166, none of which are defined in requirements.md — that branch defined DR-167..171 instead. Those references are orphaned and want a look; nothing here touches them.
This commit is contained in:
+22
-3
@@ -870,13 +870,32 @@ async getDownloads(userId: string, statusFilter: string[] | null) : Promise<Down
|
||||
return await TAURI_INVOKE("get_downloads", { userId, statusFilter });
|
||||
},
|
||||
/**
|
||||
* Pause a download
|
||||
* Pause a download.
|
||||
*
|
||||
* Writing `status = 'paused'` is only half of it, and used to be all of it: the
|
||||
* streaming task knew nothing about the row and kept running, then overwrote it
|
||||
* with `completed`/`failed` when it finished. The row flicked to "paused" and
|
||||
* undid itself — the reported "pause does not work". Signalling the worker is
|
||||
* what actually stops the bytes; it leaves the `.part` file in place so
|
||||
* [`resume_download`] can continue from it.
|
||||
*
|
||||
* A queued (not yet started) download has no worker to signal, and the status
|
||||
* write alone is enough — the pump skips anything that is not `pending`.
|
||||
*
|
||||
* TRACES: UR-055 | DR-168
|
||||
*/
|
||||
async pauseDownload(downloadId: number) : Promise<null> {
|
||||
return await TAURI_INVOKE("pause_download", { downloadId });
|
||||
},
|
||||
/**
|
||||
* Resume a paused download
|
||||
* Resume a paused download.
|
||||
*
|
||||
* Flipping the row back to `pending` is likewise not enough on its own: the
|
||||
* pump is not a poller, it runs when something calls it, so a resumed download
|
||||
* sat untouched until some unrelated event happened to pump the queue. That is
|
||||
* the other half of "resume does not work".
|
||||
*
|
||||
* TRACES: UR-055 | DR-168
|
||||
*/
|
||||
async resumeDownload(downloadId: number) : Promise<null> {
|
||||
return await TAURI_INVOKE("resume_download", { downloadId });
|
||||
@@ -2063,7 +2082,7 @@ export type Library = { id: string; name: string; collectionType: string; imageT
|
||||
* collection-type → category table any more than an item-type one. See
|
||||
* `SearchScope::for_collection_type`.
|
||||
*
|
||||
* TRACES: UR-075 | DR-164
|
||||
* TRACES: UR-075 | DR-173
|
||||
*/
|
||||
favoritesScope?: SearchScope | null }
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Called once the bitmap is decoded, with its intrinsic pixel size. Lets a
|
||||
* layout that sizes boxes from artwork (the mosaic) use the shape the image
|
||||
* actually has rather than the one its item type suggests.
|
||||
* TRACES: UR-075 | DR-163
|
||||
* TRACES: UR-075 | DR-172
|
||||
*/
|
||||
onNaturalSize?: (width: number, height: number) => void;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
arrives over a few hundred milliseconds, and re-packing on each arrival would
|
||||
shuffle the grid under the viewer's cursor several times over.
|
||||
|
||||
TRACES: UR-075 | DR-163
|
||||
TRACES: UR-075 | DR-172
|
||||
-->
|
||||
<script lang="ts" generics="T extends { key: string; ratio: number }">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
lines would no longer line up with its neighbours. Keeping everything inside
|
||||
the box is what lets `layoutMosaic` own the geometry completely.
|
||||
|
||||
TRACES: UR-075 | DR-163
|
||||
TRACES: UR-075 | DR-172
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// `favoritesScope` (Rust: `SearchScope::for_collection_type`). This file only
|
||||
// decides what to *call* it and where to put it.
|
||||
//
|
||||
// TRACES: UR-075, UR-067 | DR-163, DR-164 | UT-162
|
||||
// TRACES: UR-075, UR-067 | DR-172, DR-173 | UT-167
|
||||
|
||||
import type { Library } from "$lib/api/types";
|
||||
import {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//
|
||||
// Presentation only — nothing here knows what a library or a media item is.
|
||||
//
|
||||
// TRACES: UR-075 | DR-163 | UT-158, UT-159, UT-160
|
||||
// TRACES: UR-075 | DR-172 | UT-158, UT-159, UT-160
|
||||
|
||||
/** A tile to place: an opaque key and the aspect ratio (width / height) to honour. */
|
||||
export interface MosaicInput {
|
||||
|
||||
@@ -41,7 +41,7 @@ export function resolveFavoritesScope(raw: string | null | undefined): Favorites
|
||||
* than folded into "all": a caller asking "which category is this?" wants no
|
||||
* answer, not the cross-category one.
|
||||
*
|
||||
* TRACES: UR-075 | DR-164
|
||||
* TRACES: UR-075 | DR-173
|
||||
*/
|
||||
export function asFavoritesScope(
|
||||
scope: SearchScope | null | undefined,
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
// The shortcut strip is a mosaic row: one height, each tile as wide as its own
|
||||
// artwork. It used to force 16:9 on everything so square music covers lined up
|
||||
// with wide backdrops — which lined them up by cropping the covers.
|
||||
// TRACES: UR-075 | DR-163
|
||||
// TRACES: UR-075 | DR-172
|
||||
const LIBRARY_STRIP_HEIGHT = 132;
|
||||
const libraryTiles = $derived(
|
||||
shortcutLibraries.map((lib) => ({ key: lib.id, ratio: assumedLibraryRatio(lib), library: lib }))
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// The overview is a mosaic: rows of one height, tiles of their own widths, so
|
||||
// a square music cover sits beside a wide backdrop without either being
|
||||
// cropped to the other's shape. Each category also gets a favourites tile of
|
||||
// its own, beside the library it belongs to. TRACES: UR-075 | DR-163, DR-164
|
||||
// its own, beside the library it belongs to. TRACES: UR-075 | DR-172, DR-173
|
||||
const mosaicEntries = $derived(buildLibraryMosaic(visibleLibraries));
|
||||
|
||||
// Track if we've done an initial load and previous server state
|
||||
@@ -255,7 +255,7 @@
|
||||
category's own favourites sits beside its library — a labelled tile
|
||||
at the same weight as a library is the difference between a feature
|
||||
people find and one they don't. ux-flows §5C.2.
|
||||
TRACES: UR-067, UR-075 | DR-117, DR-163 -->
|
||||
TRACES: UR-067, UR-075 | DR-117, DR-172 -->
|
||||
<MosaicGrid items={mosaicEntries} gap={8}>
|
||||
{#snippet tile(entry)}
|
||||
{#if entry.kind === "favorites"}
|
||||
|
||||
Reference in New Issue
Block a user