feat(library): album-identity mode — header dropdown, Settings row, persistence
Spec 2026-07-19-local-album-grouping-mode (A2-A5 + i18n). The Albums tab
gains a third header dropdown ('Albums by folder' / 'Albums by metadata')
and Settings > Local Library a matching 'Album grouping' row — both write
the same pref: LocalLibraryState.albums-id-mode, persisted in
locallibrary_ui.json (default 'folder': compilations and box sets stay
whole; the metadata split stays opt-in for #411's use case).
The group key changes with the mode, so switching reloads the Albums set
(reload_albums) and invalidates the Artists tab (its album cache groups
the same way — a folder-mode compilation cross-lists under every artist
in all_artists, the owner's 'appears in all artists' ask). Threaded
through spawn_albums_load, seed_counts, the Plex quality-hydration
aggregate lookup, and the artists feed; myqbz_builder pins Metadata
(artist-scoped candidates, not the Albums view).
5 msgids x 8 locales (msgfmt clean); slintcheck green.
km
This commit is contained in:
15 files changed
+250
-1
No files matched your search
@@ -4750,3 +4750,18 @@ msgstr "Begrenzt durch das Qualitätslimit für {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "für dieses Gerät begrenzt"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Alben nach Ordner"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Alben nach Metadaten"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "ALBENANSICHT"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Album-Gruppierung"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Ordner: eine Karte pro Album-Ordner — ideal für Compilations und Boxsets. Metadaten: nach Album- + Künstler-Tags aufteilen."
|
||||
@@ -543,3 +543,18 @@ msgstr "Limited by the quality cap for {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "capped for this device"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Albums by folder"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Albums by metadata"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "ALBUMS VIEW"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Album grouping"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
@@ -4780,3 +4780,18 @@ msgstr "Limitado por el límite de calidad para {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "limitado para este dispositivo"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Álbumes por carpeta"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Álbumes por metadatos"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "VISTA DE ÁLBUMES"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Agrupación de álbumes"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Carpetas: una tarjeta por carpeta de álbum — ideal para compilaciones y box sets. Metadatos: separar por etiquetas de álbum + artista."
|
||||
@@ -4750,3 +4750,18 @@ msgstr "Limité par le plafond de qualité pour {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "plafonné pour cet appareil"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Albums par dossier"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Albums par métadonnées"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "VUE ALBUMS"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Regroupement des albums"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Dossiers : une carte par dossier d'album — idéal pour les compilations et coffrets. Métadonnées : séparer par tags album + artiste."
|
||||
@@ -4738,3 +4738,18 @@ msgstr "{}の音質上限により制限されています"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "このデバイス向けに上限適用中"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "フォルダー別アルバム"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "メタデータ別アルバム"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "アルバムビュー"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "アルバムのグループ化"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "フォルダー: アルバムフォルダーごとに1枚のカード — コンピレーションやボックスセットに最適。メタデータ: アルバム+アーティストのタグで分割。"
|
||||
@@ -4762,3 +4762,18 @@ msgstr "Beperkt door de kwaliteitslimiet voor {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "begrensd voor dit apparaat"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Albums per map"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Albums per metadata"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "ALBUMWEERGAVE"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Albumgroepering"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Mappen: één kaart per albummap — ideaal voor compilaties en boxsets. Metadata: splitsen op album- + artiesttags."
|
||||
@@ -4750,3 +4750,18 @@ msgstr "Limitado pelo limite de qualidade para {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "limitado para este dispositivo"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Álbuns por pasta"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Álbuns por metadados"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "VISTA DE ÁLBUNS"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Agrupamento de álbuns"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Pastas: um cartão por pasta de álbum — ideal para compilações e box sets. Metadados: dividir por etiquetas de álbum + artista."
|
||||
@@ -4764,3 +4764,18 @@ msgstr "Ограничено пределом качества для {}"
|
||||
|
||||
msgid "capped for this device"
|
||||
msgstr "ограничено для этого устройства"
|
||||
|
||||
msgid "Albums by folder"
|
||||
msgstr "Альбомы по папкам"
|
||||
|
||||
msgid "Albums by metadata"
|
||||
msgstr "Альбомы по метаданным"
|
||||
|
||||
msgid "ALBUMS VIEW"
|
||||
msgstr "ВИД АЛЬБОМОВ"
|
||||
|
||||
msgid "Album grouping"
|
||||
msgstr "Группировка альбомов"
|
||||
|
||||
msgid "Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags."
|
||||
msgstr "Папки: одна карточка на папку альбома — лучше для сборников и бокс-сетов. Метаданные: разделение по тегам альбома + исполнителя."
|
||||
@@ -838,6 +838,25 @@ export component LocalLibraryView inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Album identity ("Albums by") — what one album IS: a folder
|
||||
// (compilations/box sets stay whole) or metadata tag pairs
|
||||
// (split per album+artist, #411). Persisted; reloads the set.
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzSelect {
|
||||
menu-width: 190px;
|
||||
sm: true;
|
||||
options: [
|
||||
@tr("Albums by folder"),
|
||||
@tr("Albums by metadata"),
|
||||
];
|
||||
current-index: LocalLibraryState.albums-id-mode == "metadata" ? 1 : 0;
|
||||
selected(i) => {
|
||||
LocalLibraryActions.albums-set-id-mode(
|
||||
i == 1 ? "metadata" : "folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Quality/format/source filter (popup) + active-count badge.
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
import { Theme } from "../foundation/semantic-colors.slint";
|
||||
import { Typography } from "../foundation/typography.slint";
|
||||
import { Radius } from "../foundation/radius.slint";
|
||||
import { LibraryFoldersState, LibraryManageActions, LibraryScanState, PlexSettingsState, PlexAuthActions , UiFocusState } from "../state.slint";
|
||||
import { LibraryFoldersState, LibraryManageActions, LibraryScanState, PlexSettingsState, PlexAuthActions , UiFocusState, LocalLibraryState, LocalLibraryActions } from "../state.slint";
|
||||
import { SettingRow } from "SettingRow.slint";
|
||||
import { QbzIcon } from "../primitives/QbzIcon.slint";
|
||||
import { QbzCheckbox } from "../primitives/QbzCheckbox.slint";
|
||||
import { QbzToggle } from "../primitives/QbzToggle.slint";
|
||||
import { QbzSelect } from "../primitives/QbzSelect.slint";
|
||||
import { ExpandableSearch } from "../primitives/ExpandableSearch.slint";
|
||||
import { ScrollView, LineEdit } from "std-widgets.slint";
|
||||
|
||||
@@ -421,6 +422,32 @@ export component LocalLibrarySettings inherits VerticalLayout {
|
||||
|
||||
Rectangle { height: 22px; }
|
||||
|
||||
// --- Albums view -------------------------------------------------------
|
||||
// Same pref as the Albums-tab header dropdown — this is the discoverable
|
||||
// home, the header is the quick switch (both write albums-id-mode).
|
||||
GroupHeader { text: @tr("ALBUMS VIEW"); }
|
||||
SettingRow {
|
||||
label: @tr("Album grouping");
|
||||
description: @tr("Folders: one card per album folder — best for compilations and box sets. Metadata: split by album + artist tags.");
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzSelect {
|
||||
menu-width: 190px;
|
||||
sm: true;
|
||||
options: [
|
||||
@tr("Albums by folder"),
|
||||
@tr("Albums by metadata"),
|
||||
];
|
||||
current-index: LocalLibraryState.albums-id-mode == "metadata" ? 1 : 0;
|
||||
selected(i) => {
|
||||
LocalLibraryActions.albums-set-id-mode(i == 1 ? "metadata" : "folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { height: 22px; }
|
||||
|
||||
// --- Maintenance -----------------------------------------------------
|
||||
GroupHeader { text: @tr("MAINTENANCE"); }
|
||||
SettingRow {
|
||||
|
||||
@@ -1194,6 +1194,12 @@ export global LocalLibraryState {
|
||||
in property <[AlbumCardItem]> albums-visible: [];
|
||||
in property <[DiscoverSection]> albums-grouped: [];
|
||||
in-out property <string> albums-group: "off"; // off | alpha | artist
|
||||
// Album IDENTITY mode — what one "album" IS on the Albums tab:
|
||||
// "folder" (one card per album-root folder; default — compilations/box
|
||||
// sets stay whole) | "metadata" (split by album+artist tags, #411).
|
||||
// Persisted in locallibrary_ui.json; switching re-queries the DB (unlike
|
||||
// sort/group, which re-derive client-side).
|
||||
in-out property <string> albums-id-mode: "folder";
|
||||
in property <[AlphaJump]> albums-alpha: []; // A-Z jumps (alpha group)
|
||||
in property <int> albums-shown: 0; // count after filter
|
||||
in-out property <bool> albums-multi-select: false; // album checkboxes on
|
||||
@@ -1318,6 +1324,9 @@ export global LocalLibraryActions {
|
||||
callback albums-set-sort(string /* sort key */);
|
||||
// Set group mode (off|alpha|artist) + re-derive.
|
||||
callback albums-set-group(string /* mode */);
|
||||
// Set the album identity mode (folder|metadata) + persist + reload the
|
||||
// albums set (the group key changes — a derive is not enough).
|
||||
callback albums-set-id-mode(string /* mode */);
|
||||
// Set grid|list view.
|
||||
callback albums-set-view(string /* mode */);
|
||||
// A quality/format/source filter toggle changed -> re-derive.
|
||||
|
||||
Reference in new issue
Block a user