Requested directly: "lets add some themeing into it now, perhaps
under the configuration, have white/black, and some more colors."
There was no existing app-wide Settings/Configuration surface -
every prior setting lived in its own panel-specific modal (Fetch
Data Settings, subtitle provider settings) - so this adds the
app's first one: a palette-icon button in the sidebar footer opens
a new Settings modal with a 2x2 grid of theme swatches.
Four themes: Aurora (the existing dark teal/green look, unchanged,
stays the default), Light (a clean white/black theme - the literal
"white/black" ask), Ocean (a cool blue-toned dark variant), and
Sunset (a warm amber-toned dark variant) - the "some more colors"
part. Picking one applies instantly via a `data-theme` attribute on
<html> and persists through new get_theme/save_theme commands
(added to settings.rs/lib.rs alongside delivery 25's movie-naming-
scheme fix), applied on every future launch by a boot-time effect
in App.tsx so it takes effect even if Settings is never reopened.
theme.css's variable set was expanded to cover every place a color
was previously hardcoded outside the existing --dock/--surface/etc.
variables, so the whole app actually re-themes instead of leaving
dark boxes behind on the Light theme: button resting/hover/active
shades, the Load-files popup background, the primary button's hover
tint, the header's gradient stops, and five levels of white-tint
row/button hover highlights (RenamePanel.css/Header.css) all moved
to new variables (--btn-bg*, --popup-bg, --accent-hover, --header-
grad-a/b, --tint-02/03/05/06/16) with theme-specific values - the
light theme in particular needed dark tints instead of white ones
for hover states to stay visible on a white background.
Verified with a new Playwright script covering: default theme on a
fresh install, the Settings modal listing all 4 themes with the
right one marked selected, clicking a theme applying it immediately
(actual computed background color and CSS variable checked, not
just the data-theme attribute) and saving it, and a previously-saved
theme applying on boot before Settings is ever opened. Screenshots
taken of all 4 themes across the main view and the Naming Scheme
editor (whose buttons/popups were part of the hardcoded-color
cleanup) to confirm visually. All prior verification suites (47
checks across naming-scheme/match-fetch/hash-files/movie-scheme),
`cargo test --workspace` (162 tests), and `npm run build` still
pass clean.
Closes the last remaining gap in porting-roadmap item 1 (full naming-
scheme bindings) - user picked this from a short list of next-feature
options after the recent naming-scheme/Match usability work.
crates/aurora-curator-core/src/sfv: new compute_all_checksums(path),
alongside the existing compute_checksum(path, kind). Streams the file
ONCE, updating CRC32/MD5/SHA-1 hashers concurrently over each chunk,
rather than calling compute_checksum three times (three full reads of
what's often a multi-gigabyte video file). The SFV panel itself keeps
using compute_checksum directly - it only ever needs one algorithm at a
time, picked by the user, so computing the other two nobody asked for
would be wasteful in the other direction. 3 new tests: matches known
CRC32/MD5/SHA-1 test vectors together, agrees with compute_checksum on a
file bigger than the read buffer (catches a hasher only seeing the first
chunk), errors on a missing file.
src-tauri/src/sfv.rs: new NamingHashOutcome struct (plain
#[serde(rename_all = "camelCase")] struct, not a tagged enum - the class
of bug fixed in the nineteenth delivery doesn't apply here) and
compute_naming_hashes command, batching compute_all_checksums the same
blocking-thread way compute_checksums already does, with the same
per-file error isolation (one bad file doesn't abort the batch).
Registered in lib.rs.
RenamePanel.tsx: new runHashFiles() and a "Hash Files" button (new
HashIcon in Icons.tsx) next to Fetch Data. Deliberately NOT wired into
Match automatically like the rest of its local steps - hashing reads a
file's entire contents rather than a small header, so running it
unasked on every Match click for every loaded file would make Match
unpredictably slow. Its own busy state (hashing) disables Match/Fetch
Data/Hash Files against each other while any one is running. New "File
hashing" field-reference group ({crc32}/{md5}/{sha1} as clickable chips,
reusing the field-chip insert-at-cursor mechanism from the earlier
naming-scheme UX delivery) and updated inline help text.
Verified via cargo test --workspace (191 -> 193 in the core crate: 145 ->
148) + cargo check --workspace (clean) + npm run build (clean) + a
10-check Playwright script against npm run dev (mocking
window.__TAURI_INTERNALS__.invoke): confirmed the three field chips are
present, Hash Files calls compute_naming_hashes with every loaded path,
the status line correctly reports hashed-vs-failed counts, a computed
CRC32 reaches the live rename preview, a failed file's row doesn't
fabricate a hash, and clicking Hash Files with nothing loaded is handled
gracefully. Caught one test-mock bug along the way (not an app bug): an
early mock response for a successful hash omitted the `error` field
entirely rather than setting it to `null`, which the app correctly (per
the real Rust command's always-present Option<String> field) treated as
a truthy non-null value and skipped merging - fixed the mock to match
the real wire contract.
Updated README (status paragraph, project layout for sfv.rs's now-four
commands, a new "Hash Files" section placed after "Real media-file
probing", porting roadmap item 1's "still missing" list).