Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/features/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ Which columns the track table shows, in what order and how wide, per profile in

Five things that are easy to get wrong here, and are not:

- **Names sort under `FOLD`, not `NOCASE`.** SQLite's `NOCASE` folds ASCII only, and the scanner's `canonical_name` / `canonical_title` keep their accents, so "Émilie" sorted after "Zazie" while the A-Z rail filed her under E. [`collation.rs`](../../src-tauri/crates/core/src/repository/sqlite/collation.rs) defines a `FOLD` collation that sets case and accents aside (every decomposable accent through NFD, plus the letters NFD leaves whole, so a mirrored row's `normalize_name` key sorts next to a local one that kept its accents; only then are ties broken on the lowercased and the original strings, so two distinct keys never compare equal), then breaks ties on case and bytes so the order stays total. The profile pool registers it on every connection (`collation::register` in [`profile_db.rs`](../../src-tauri/crates/app/src/db/profile_db.rs)); a query naming it on a connection opened any other way fails to prepare, so a test pool that runs a listing registers it too. Paths, codecs, keys and the folder browser's grouping keep `NOCASE`.
- **Sorting happens in SQL, over a whitelist.** `browse::track_sort_expr` maps a column id to an expression; anything unmatched falls back to the default clause, which is the only reason the caller may hand the result to `AssertSqlSafe`. Nullable columns put their NULLs last **in both directions** — an untagged track is not a track with the smallest value — and every sort carries a tie-break so two identical queries cannot return two different orders. The previous shape spelled out two `match` arms per column and had quietly stopped at seven of them.
- **The resize handle lives outside the sort button.** Inside it, a press to widen the column fires the sort on release, so every resize reorders the list.
- **"Fit to content" measures through a canvas, not the DOM.** The rows are virtualised, so the ones outside the viewport have no computed layout and a DOM measurement would size the column to whatever happened to be on screen. The **header label is measured too**, in the header's own (uppercase, bold, letter-spaced) font: a column fitted to short content otherwise shows a truncated title, which reads as the fit having failed.
Expand Down
30 changes: 20 additions & 10 deletions docs/rfcs/RFC-005-remote-source-and-sync-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -810,16 +810,26 @@ RFC — now written, as
Two things the query has to get right, and both are about the halves being
comparable rather than merely concatenated:

- **The sort keys are normalised on both sides.** The local half sorts on
`album.canonical_title` / `artist.canonical_name` — forms produced by
`normalize_name`, which lowercases, folds diacritics and drops punctuation.
SQLite cannot reproduce any of that (`COLLATE NOCASE` is ASCII-only), so
sorting the remote half on its raw display name puts "Björk" and "bjork" in
two different places and splits one artist in half down the middle of the
list. `remote_album.sort_title` / `sort_artist` therefore carry the same
normalised forms, computed by the mirror with the same function. A row
mirrored before those columns existed falls back to its display title, and
one walk fills it in.
- **The sort keys are comparable on both sides.** The two halves do not
spell them the same way:
- the local half sorts on `album.canonical_title` /
`artist.canonical_name`, the scanner's `canonical_name`: lowercased,
punctuation dropped, **accents kept**;
- the remote half sorts on `remote_album.sort_title` / `sort_artist`,
which the mirror computes with `normalize_name`: lowercased, punctuation
dropped, **accents folded**, `&` spelled "and".

Sorting the remote half on its raw display name instead put "Björk" and
"bjork" in two different places and split one artist in half down the
middle of the list. The unified query projects each half's key under one
alias and orders it with `COLLATE FOLD` (see
[library.md](../features/library.md)), which sets case and accents aside
first, so a local key that kept its accents sorts next to a remote one
that folded them (case and the original characters only break the tie
between them). `COLLATE NOCASE`, which the listings used
before, is ASCII-only and could not. A row mirrored before the sort
columns existed has them `NULL`, and `COALESCE` supplies its display title
and artist until a mirror walk fills them in.
- **A local library filter excludes the remote half.** The picker chooses among
_local_ libraries, and a server album belongs to none of them; leaving the
remote rows visible while the user has narrowed to one library reads as the
Expand Down
10 changes: 5 additions & 5 deletions packaging/flatpak/generated/cargo-sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -8738,14 +8738,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/wasapi/wasapi-0.24.0.crate",
"sha256": "ee144c215d8d31e94c1a599fbaf540ca82a7017e4f1786816b179f334fac751d",
"dest": "cargo/vendor/wasapi-0.24.0"
"url": "https://static.crates.io/crates/wasapi/wasapi-0.25.0.crate",
"sha256": "5225a7c681bdaf6a63aa0ffc287adba7fd5a04b592a2730643869ce45641da99",
"dest": "cargo/vendor/wasapi-0.25.0"
},
{
"type": "inline",
"contents": "{\"package\": \"ee144c215d8d31e94c1a599fbaf540ca82a7017e4f1786816b179f334fac751d\", \"files\": {}}",
"dest": "cargo/vendor/wasapi-0.24.0",
"contents": "{\"package\": \"5225a7c681bdaf6a63aa0ffc287adba7fd5a04b592a2730643869ce45641da99\", \"files\": {}}",
"dest": "cargo/vendor/wasapi-0.25.0",
"dest-filename": ".cargo-checksum.json"
},
{
Expand Down
1 change: 1 addition & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading