diff --git a/crates/qbz-ui/translations/de/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/de/LC_MESSAGES/qbz-ui.po index 21c78c3c3..36e6a4e23 100644 --- a/crates/qbz-ui/translations/de/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/de/LC_MESSAGES/qbz-ui.po @@ -4660,3 +4660,45 @@ msgstr "Titel auswählen" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz weist Anfragen vorübergehend ab – kurze Pause. Bitte gleich erneut versuchen." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "FLATPAK-SANDBOX" + +msgid "SNAP SANDBOX" +msgstr "SNAP-SANDBOX" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ läuft in einer Flatpak-Sandbox. Manche Funktionen brauchen einmalige Berechtigungen — führe die Befehle in einem Terminal aus und starte QBZ danach neu. Die Berechtigungen bleiben über Updates hinweg erhalten." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ läuft in einer Snap-Sandbox. Manche Audio-Schnittstellen müssen einmalig verbunden werden — führe diese Befehle in einem Terminal aus und starte QBZ danach neu." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Exklusiver DAC-Zugriff (Bit-perfekt)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Empfohlen für den exklusiven Modus: QBZ kann PipeWire bitten, den DAC sauber zu übergeben (D-Bus-Gerätereservierung)." + +msgid "Music on NAS or external drives" +msgstr "Musik auf NAS oder externen Laufwerken" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Gibt Zugriff auf einen Ordner außerhalb der Sandbox. Wiederhole den Befehl für jeden Ordner, den du brauchst." + +msgid "Required audio connections" +msgstr "Erforderliche Audio-Verbindungen" + +msgid "Optional — external drives & NAS" +msgstr "Optional — externe Laufwerke & NAS" + +msgid "Copy" +msgstr "Kopieren" + +msgid "Copied!" +msgstr "Kopiert!" diff --git a/crates/qbz-ui/translations/en/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/en/LC_MESSAGES/qbz-ui.po index 14635d90a..b05407076 100644 --- a/crates/qbz-ui/translations/en/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/en/LC_MESSAGES/qbz-ui.po @@ -453,3 +453,45 @@ msgstr "Select tracks" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz is temporarily refusing requests — backing off. Try again shortly." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "FLATPAK SANDBOX" + +msgid "SNAP SANDBOX" +msgstr "SNAP SANDBOX" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Exclusive DAC access (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." + +msgid "Music on NAS or external drives" +msgstr "Music on NAS or external drives" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." + +msgid "Required audio connections" +msgstr "Required audio connections" + +msgid "Optional — external drives & NAS" +msgstr "Optional — external drives & NAS" + +msgid "Copy" +msgstr "Copy" + +msgid "Copied!" +msgstr "Copied!" diff --git a/crates/qbz-ui/translations/es/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/es/LC_MESSAGES/qbz-ui.po index edf6ac78b..744d3fbce 100644 --- a/crates/qbz-ui/translations/es/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/es/LC_MESSAGES/qbz-ui.po @@ -4690,3 +4690,45 @@ msgstr "Seleccionar pistas" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz está rechazando solicitudes temporalmente; esperando un momento. Intenta de nuevo en breve." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "SANDBOX DE FLATPAK" + +msgid "SNAP SANDBOX" +msgstr "SANDBOX DE SNAP" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ se está ejecutando dentro de un sandbox de Flatpak. Algunas funciones necesitan permisos que se otorgan una sola vez: ejecuta los comandos en una terminal y reinicia QBZ. Los permisos se conservan entre actualizaciones." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ se está ejecutando dentro de un sandbox de Snap. Algunas interfaces de audio necesitan conectarse una sola vez: ejecuta estos comandos en una terminal y reinicia QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Acceso exclusivo al DAC (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Recomendado para el modo exclusivo: permite que QBZ le pida a PipeWire que entregue el DAC limpiamente (reserva de dispositivo por D-Bus)." + +msgid "Music on NAS or external drives" +msgstr "Música en NAS o discos externos" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Da acceso a una carpeta fuera del sandbox. Repite el comando por cada carpeta que necesites." + +msgid "Required audio connections" +msgstr "Conexiones de audio requeridas" + +msgid "Optional — external drives & NAS" +msgstr "Opcional — discos externos y NAS" + +msgid "Copy" +msgstr "Copiar" + +msgid "Copied!" +msgstr "¡Copiado!" diff --git a/crates/qbz-ui/translations/fr/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/fr/LC_MESSAGES/qbz-ui.po index 3e88a18b1..666fea856 100644 --- a/crates/qbz-ui/translations/fr/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/fr/LC_MESSAGES/qbz-ui.po @@ -4660,3 +4660,45 @@ msgstr "Sélectionner des pistes" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz refuse temporairement les requêtes — pause en cours. Réessayez dans un instant." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "SANDBOX FLATPAK" + +msgid "SNAP SANDBOX" +msgstr "SANDBOX SNAP" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ s'exécute dans un sandbox Flatpak. Certaines fonctions nécessitent des autorisations à accorder une seule fois — exécutez les commandes dans un terminal, puis redémarrez QBZ. Les autorisations sont conservées après les mises à jour." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ s'exécute dans un sandbox Snap. Certaines interfaces audio doivent être connectées une seule fois — exécutez ces commandes dans un terminal, puis redémarrez QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Accès exclusif au DAC (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Recommandé pour le mode exclusif : permet à QBZ de demander à PipeWire de céder le DAC proprement (réservation de périphérique D-Bus)." + +msgid "Music on NAS or external drives" +msgstr "Musique sur NAS ou disques externes" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Donne accès à un dossier hors du sandbox. Répétez la commande pour chaque dossier nécessaire." + +msgid "Required audio connections" +msgstr "Connexions audio requises" + +msgid "Optional — external drives & NAS" +msgstr "Optionnel — disques externes et NAS" + +msgid "Copy" +msgstr "Copier" + +msgid "Copied!" +msgstr "Copié !" diff --git a/crates/qbz-ui/translations/ja/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/ja/LC_MESSAGES/qbz-ui.po index fa170a424..fc15b56fb 100644 --- a/crates/qbz-ui/translations/ja/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/ja/LC_MESSAGES/qbz-ui.po @@ -4648,3 +4648,45 @@ msgstr "トラックを選択" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuzが一時的にリクエストを拒否しています。少し待って再試行してください。" + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "FLATPAK サンドボックス" + +msgid "SNAP SANDBOX" +msgstr "SNAP サンドボックス" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ は Flatpak サンドボックス内で動作しています。一部の機能には一度だけの権限付与が必要です。コマンドをターミナルで実行してから QBZ を再起動してください。権限はアップデート後も保持されます。" + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ は Snap サンドボックス内で動作しています。一部のオーディオインターフェースは一度だけ接続する必要があります。これらのコマンドをターミナルで実行してから QBZ を再起動してください。" + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "DAC 排他アクセス(ビットパーフェクト)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "排他モードに推奨:PipeWire に DAC のクリーンな引き渡しを要求できます(D-Bus デバイス予約)。" + +msgid "Music on NAS or external drives" +msgstr "NAS や外部ドライブの音楽" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "サンドボックス外のフォルダへのアクセスを許可します。必要なフォルダごとにコマンドを繰り返してください。" + +msgid "Required audio connections" +msgstr "必須のオーディオ接続" + +msgid "Optional — external drives & NAS" +msgstr "任意 — 外部ドライブと NAS" + +msgid "Copy" +msgstr "コピー" + +msgid "Copied!" +msgstr "コピーしました!" diff --git a/crates/qbz-ui/translations/nl/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/nl/LC_MESSAGES/qbz-ui.po index 67f6fecf7..5921d51cb 100644 --- a/crates/qbz-ui/translations/nl/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/nl/LC_MESSAGES/qbz-ui.po @@ -4672,3 +4672,45 @@ msgstr "Nummers selecteren" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz weigert tijdelijk verzoeken — even pauzeren. Probeer het zo opnieuw." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "FLATPAK-SANDBOX" + +msgid "SNAP SANDBOX" +msgstr "SNAP-SANDBOX" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ draait in een Flatpak-sandbox. Sommige functies hebben eenmalige rechten nodig — voer de commando's in een terminal uit en herstart daarna QBZ. De rechten blijven na updates behouden." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ draait in een Snap-sandbox. Sommige audio-interfaces moeten eenmalig worden gekoppeld — voer deze commando's in een terminal uit en herstart daarna QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Exclusieve DAC-toegang (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Aanbevolen voor de exclusieve modus: laat QBZ PipeWire vragen de DAC netjes vrij te geven (D-Bus-apparaatreservering)." + +msgid "Music on NAS or external drives" +msgstr "Muziek op NAS of externe schijven" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Geeft toegang tot een map buiten de sandbox. Herhaal het commando voor elke map die je nodig hebt." + +msgid "Required audio connections" +msgstr "Vereiste audiokoppelingen" + +msgid "Optional — external drives & NAS" +msgstr "Optioneel — externe schijven & NAS" + +msgid "Copy" +msgstr "Kopiëren" + +msgid "Copied!" +msgstr "Gekopieerd!" diff --git a/crates/qbz-ui/translations/pt/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/pt/LC_MESSAGES/qbz-ui.po index b082cc2a9..032c0ecdc 100644 --- a/crates/qbz-ui/translations/pt/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/pt/LC_MESSAGES/qbz-ui.po @@ -4660,3 +4660,45 @@ msgstr "Selecionar faixas" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "O Qobuz está recusando solicitações temporariamente — aguardando. Tente novamente em breve." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "SANDBOX FLATPAK" + +msgid "SNAP SANDBOX" +msgstr "SANDBOX SNAP" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "O QBZ está a correr dentro de uma sandbox Flatpak. Algumas funcionalidades precisam de permissões concedidas uma única vez — execute os comandos num terminal e reinicie o QBZ. As permissões mantêm-se entre atualizações." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "O QBZ está a correr dentro de uma sandbox Snap. Algumas interfaces de áudio precisam de ser ligadas uma única vez — execute estes comandos num terminal e reinicie o QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Acesso exclusivo ao DAC (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Recomendado para o modo exclusivo: permite ao QBZ pedir ao PipeWire que entregue o DAC de forma limpa (reserva de dispositivo via D-Bus)." + +msgid "Music on NAS or external drives" +msgstr "Música em NAS ou discos externos" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Concede acesso a uma pasta fora da sandbox. Repita o comando para cada pasta necessária." + +msgid "Required audio connections" +msgstr "Ligações de áudio obrigatórias" + +msgid "Optional — external drives & NAS" +msgstr "Opcional — discos externos e NAS" + +msgid "Copy" +msgstr "Copiar" + +msgid "Copied!" +msgstr "Copiado!" diff --git a/crates/qbz-ui/translations/ru/LC_MESSAGES/qbz-ui.po b/crates/qbz-ui/translations/ru/LC_MESSAGES/qbz-ui.po index f6d1d4af3..6d8e73227 100644 --- a/crates/qbz-ui/translations/ru/LC_MESSAGES/qbz-ui.po +++ b/crates/qbz-ui/translations/ru/LC_MESSAGES/qbz-ui.po @@ -4674,3 +4674,45 @@ msgstr "Выбрать треки" msgid "Qobuz is temporarily refusing requests — backing off. Try again shortly." msgstr "Qobuz временно отклоняет запросы — пауза. Повторите попытку чуть позже." + +msgid "Flatpak" +msgstr "Flatpak" + +msgid "Snap" +msgstr "Snap" + +msgid "FLATPAK SANDBOX" +msgstr "ПЕСОЧНИЦА FLATPAK" + +msgid "SNAP SANDBOX" +msgstr "ПЕСОЧНИЦА SNAP" + +msgid "QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates." +msgstr "QBZ работает внутри песочницы Flatpak. Некоторым функциям нужны разрешения, выдаваемые один раз, — выполните команды в терминале и перезапустите QBZ. Разрешения сохраняются между обновлениями." + +msgid "QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ." +msgstr "QBZ работает внутри песочницы Snap. Некоторые аудиоинтерфейсы нужно подключить один раз — выполните эти команды в терминале и перезапустите QBZ." + +msgid "Exclusive DAC access (bit-perfect)" +msgstr "Эксклюзивный доступ к ЦАП (bit-perfect)" + +msgid "Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)." +msgstr "Рекомендуется для эксклюзивного режима: позволяет QBZ попросить PipeWire корректно освободить ЦАП (резервирование устройства через D-Bus)." + +msgid "Music on NAS or external drives" +msgstr "Музыка на NAS или внешних дисках" + +msgid "Grants access to a folder outside the sandbox. Repeat the command for each folder you need." +msgstr "Даёт доступ к папке вне песочницы. Повторите команду для каждой нужной папки." + +msgid "Required audio connections" +msgstr "Необходимые аудиоподключения" + +msgid "Optional — external drives & NAS" +msgstr "Опционально — внешние диски и NAS" + +msgid "Copy" +msgstr "Копировать" + +msgid "Copied!" +msgstr "Скопировано!" diff --git a/crates/qbz-ui/ui/app.slint b/crates/qbz-ui/ui/app.slint index 66f037ee7..081636801 100644 --- a/crates/qbz-ui/ui/app.slint +++ b/crates/qbz-ui/ui/app.slint @@ -31,7 +31,7 @@ export { ThemeState } from "foundation/theme-state.slint"; export { Typography } from "foundation/typography.slint"; // Re-export the state globals so the Rust layer can populate them. -export { HomeState, HomeActions, RecentAlbumsState, DiscoverState, DiscoverActions, SectionDescriptor, ConfigRow, DiscoverBrowseState, DiscoverBrowseActions, PlaylistBrowseState, PlaylistBrowseActions, ForYouState, PinnedItem, PinnedState, PinnedActions, ExternalRecoState, ExternalRecoActions, MixState, GenreFilterState, GenreFilterActions, AlbumState, ArtistState, NavState, ShellState, SessionState, SettingsState, AlbumActions, ArtistActions, ArtworkActions, NowPlayingState, QueueState, LyricsState, LyricsLineItem, SearchState, SearchActions, NetworkSidebarState, NetworkSidebarActions, MusicianState, MusicianActions, LabelState, LabelActions, AwardState, AwardActions, AwardEntry, ArtistReleasesState, ArtistReleasesActions, LocationViewState, LocationViewActions, FavoritesState, FavoritesActions, LibraryFeedItem, LibraryAllState, LibraryAllActions, PlaylistPickerState, PlaylistPickerActions, DuplicateConfirmState, DuplicateConfirmActions, PlaylistState, PlaylistActions, SidebarState, SidebarActions, SidebarFolderPopupState, CreatePlaylistState, CreatePlaylistActions, EditPlaylistState, EditPlaylistActions, CreateFolderState, CreateFolderActions, SettingsExportState, SettingsExportActions, MyQbzCreateState, MyQbzCreateActions, DragState, DragActions, PlaylistManagerState, PlaylistManagerActions, OfflineManagerState, OfflineManagerActions, BlacklistState, BlacklistActions, BlacklistedArtistItem, MyQbzState, MyQbzActions, MixtapeCardItem, MyQbzAddState, MyQbzAddActions, MyQbzAddRow, MyQbzDetailState, MyQbzDetailActions, MixtapeDetailItem, MyQbzEditState, MyQbzEditActions, MyQbzMixState, MyQbzMixActions, DiscoBuilderState, DiscoBuilderActions, DiscoGroup, DiscoCandidate, LocalLibraryState, LocalLibraryActions, LibraryFoldersState, LibFolderEditState, LibraryManageActions, LibraryScanState, LibAlbumFilterState, LocalAlbumState, LocalAlbumActions, TagEditorState, TagEditorActions, FolderEditState, FolderEditActions, ToastState, TextUtil, QconnectDevState, QconnectDevice, CastState, CastDevice, CastActions, AppearanceState, MyQbzBrandingState, EphemeralPlayChoiceState, EphemeralPlayChoiceActions, PlexSettingsState, PlexAuthActions, PlexSectionItem, ScrobbleState, ScrobbleActions, DiscordState, OfflineState, LoginState, OfflineModeActions, OfflineFavoritesState, OfflineFavoritesActions, ImportLogEntry, PlaylistImportState, PlaylistImportActions, DacWizardState, DacWizardActions, DacCandidateRow, RemediationRow, DacConfigRow, InfoCreditRow, InfoCreditPair, AlbumCreditPerformer, AlbumCreditTrack, TrackInfoState, TrackInfoActions, AlbumInfoState, AlbumInfoActions, BookletState, BookletActions, SuggestionsState, SuggestionsActions, SuggestionCard, PlaylistSuggestionsState, PlaylistSuggestionsActions, PlaylistSuggestionRow, VisualizerState, ImmersiveState, ImmersiveSearchActions, ImmersiveActions, MiniPlayerState, WindowControlActions, PurchasesState, PurchasesActions, PurchaseAlbumItem, PurchaseTrackItem, PurchaseAlbumGroup, PurchaseTrackGroup, PurchaseFormatItem, PurchaseDetailState, PurchaseDetailActions, PurchaseDetailTrack, KeybindingRow, KeybindingCategoryGroup, KeybindingsState, KeybindingsActions, KeyboardShortcutsState, LinkResolverState, LinkResolverActions, UiFocusState, UiScale, SleepTimerState, SleepTimerActions, LogRow, LogViewerState, DiagRow, DiagnosticsState, ReportIssueState, ReportIssueActions, AboutState, AboutActions, AboutContributorRow, AboutContributorGroup, WhatsNewState, WhatsNewActions, WhatsNewBlock, WhatsNewTocEntry } from "state.slint"; +export { HomeState, HomeActions, RecentAlbumsState, DiscoverState, DiscoverActions, SectionDescriptor, ConfigRow, DiscoverBrowseState, DiscoverBrowseActions, PlaylistBrowseState, PlaylistBrowseActions, ForYouState, PinnedItem, PinnedState, PinnedActions, ExternalRecoState, ExternalRecoActions, MixState, GenreFilterState, GenreFilterActions, AlbumState, ArtistState, NavState, ShellState, SessionState, SettingsState, AlbumActions, ArtistActions, ArtworkActions, NowPlayingState, QueueState, LyricsState, LyricsLineItem, SearchState, SearchActions, NetworkSidebarState, NetworkSidebarActions, MusicianState, MusicianActions, LabelState, LabelActions, AwardState, AwardActions, AwardEntry, ArtistReleasesState, ArtistReleasesActions, LocationViewState, LocationViewActions, FavoritesState, FavoritesActions, LibraryFeedItem, LibraryAllState, LibraryAllActions, PlaylistPickerState, PlaylistPickerActions, DuplicateConfirmState, DuplicateConfirmActions, PlaylistState, PlaylistActions, SidebarState, SidebarActions, SidebarFolderPopupState, CreatePlaylistState, CreatePlaylistActions, EditPlaylistState, EditPlaylistActions, CreateFolderState, CreateFolderActions, SettingsExportState, SettingsExportActions, SandboxState, MyQbzCreateState, MyQbzCreateActions, DragState, DragActions, PlaylistManagerState, PlaylistManagerActions, OfflineManagerState, OfflineManagerActions, BlacklistState, BlacklistActions, BlacklistedArtistItem, MyQbzState, MyQbzActions, MixtapeCardItem, MyQbzAddState, MyQbzAddActions, MyQbzAddRow, MyQbzDetailState, MyQbzDetailActions, MixtapeDetailItem, MyQbzEditState, MyQbzEditActions, MyQbzMixState, MyQbzMixActions, DiscoBuilderState, DiscoBuilderActions, DiscoGroup, DiscoCandidate, LocalLibraryState, LocalLibraryActions, LibraryFoldersState, LibFolderEditState, LibraryManageActions, LibraryScanState, LibAlbumFilterState, LocalAlbumState, LocalAlbumActions, TagEditorState, TagEditorActions, FolderEditState, FolderEditActions, ToastState, TextUtil, QconnectDevState, QconnectDevice, CastState, CastDevice, CastActions, AppearanceState, MyQbzBrandingState, EphemeralPlayChoiceState, EphemeralPlayChoiceActions, PlexSettingsState, PlexAuthActions, PlexSectionItem, ScrobbleState, ScrobbleActions, DiscordState, OfflineState, LoginState, OfflineModeActions, OfflineFavoritesState, OfflineFavoritesActions, ImportLogEntry, PlaylistImportState, PlaylistImportActions, DacWizardState, DacWizardActions, DacCandidateRow, RemediationRow, DacConfigRow, InfoCreditRow, InfoCreditPair, AlbumCreditPerformer, AlbumCreditTrack, TrackInfoState, TrackInfoActions, AlbumInfoState, AlbumInfoActions, BookletState, BookletActions, SuggestionsState, SuggestionsActions, SuggestionCard, PlaylistSuggestionsState, PlaylistSuggestionsActions, PlaylistSuggestionRow, VisualizerState, ImmersiveState, ImmersiveSearchActions, ImmersiveActions, MiniPlayerState, WindowControlActions, PurchasesState, PurchasesActions, PurchaseAlbumItem, PurchaseTrackItem, PurchaseAlbumGroup, PurchaseTrackGroup, PurchaseFormatItem, PurchaseDetailState, PurchaseDetailActions, PurchaseDetailTrack, KeybindingRow, KeybindingCategoryGroup, KeybindingsState, KeybindingsActions, KeyboardShortcutsState, LinkResolverState, LinkResolverActions, UiFocusState, UiScale, SleepTimerState, SleepTimerActions, LogRow, LogViewerState, DiagRow, DiagnosticsState, ReportIssueState, ReportIssueActions, AboutState, AboutActions, AboutContributorRow, AboutContributorGroup, WhatsNewState, WhatsNewActions, WhatsNewBlock, WhatsNewTocEntry } from "state.slint"; // Which top-level screen is shown. The app starts on `splash` while it // restores a saved session, then resolves to `shell` or `login`. diff --git a/crates/qbz-ui/ui/settings/SandboxSettings.slint b/crates/qbz-ui/ui/settings/SandboxSettings.slint new file mode 100644 index 000000000..1118ad423 --- /dev/null +++ b/crates/qbz-ui/ui/settings/SandboxSettings.slint @@ -0,0 +1,172 @@ +// Settings > Sandbox — the one-time permission commands for sandboxed +// installs (Tauri parity: the old Settings > Flatpak / Snap sections). +// Shown only when the app runs inside Flatpak or Snap (SandboxState. +// install-method); hidden on native/dev installs. +// +// Flatpak rows: exclusive-DAC D-Bus reservation (the user-side fix for +// discussion #641 — the Flathub manifest can't carry the wildcard own-name, +// so the user grants it locally via `flatpak override`) and filesystem +// access for NAS/external music libraries. Discord's IPC override stays in +// Integrations (already there). Snap rows: the audio interface connections +// from the Tauri section (snap name is `qbz-player`). +// +// Commands are plain strings (never translated); surrounding copy goes +// through @tr. Copy feedback is local UI state (Copied! for 1.5 s); the +// clipboard write itself is SandboxState.copy-command → share::copy_to_clipboard. + +import { Theme } from "../foundation/semantic-colors.slint"; +import { Typography } from "../foundation/typography.slint"; +import { Radius } from "../foundation/radius.slint"; +import { SandboxState } from "../state.slint"; + +component GroupHeader inherits Text { + color: Theme.text-muted; + font-size: 11px; + letter-spacing: 1.5px; + font-weight: Typography.semibold; +} + +component RowTitle inherits Text { + color: Theme.text-primary; + font-size: Typography.body; + font-weight: Typography.medium; + wrap: word-wrap; +} + +component RowNote inherits Text { + color: Theme.text-muted; + font-size: Typography.legal; + wrap: word-wrap; +} + +// Matches AudioSettings/OfflineSettings' SecondaryButton. +component SecondaryButton inherits Rectangle { + in property label; + callback clicked(); + // 160px floor keeps the settings right-edge grid; longer translations grow. + width: Math.max(label-txt.preferred-width + 32px, 160px); + height: 34px; + border-radius: Radius.sm; + border-width: 1px; + border-color: Theme.border-subtle; + background: ta.has-hover ? Theme.surface-hover : Theme.surface-elevated; + label-txt := Text { + width: 100%; + height: 100%; + text: root.label; + color: Theme.text-secondary; + font-size: Typography.body; + font-weight: Typography.medium; + horizontal-alignment: center; + vertical-alignment: center; + } + ta := TouchArea { + mouse-cursor: pointer; + clicked => { + root.clicked(); + } + } +} + +// Full-width shell-command row with copy-to-clipboard feedback. `command` +// may hold several lines; the whole block copies as one clipboard payload. +component CommandBlock inherits Rectangle { + in property command; + property copied: false; + + border-radius: Radius.sm; + border-width: 1px; + border-color: Theme.border-subtle; + background: Theme.surface-elevated; + height: cmd-layout.preferred-height; + + cmd-layout := HorizontalLayout { + padding: 10px; + spacing: 12px; + Text { + text: root.command; + color: Theme.text-primary; + font-family: "monospace"; + font-size: Typography.legal; + wrap: word-wrap; + horizontal-stretch: 1; + vertical-alignment: center; + } + VerticalLayout { + alignment: center; + SecondaryButton { + label: root.copied ? @tr("Copied!") : @tr("Copy"); + clicked => { + SandboxState.copy-command(root.command); + root.copied = true; + copied-timer.restart(); + } + } + } + } + copied-timer := Timer { + running: false; + interval: 1500ms; + triggered => { + root.copied = false; + copied-timer.stop(); + } + } +} + +export component SandboxSettings inherits VerticalLayout { + spacing: 4px; + alignment: start; + + // --- FLATPAK --------------------------------------------------------- + if SandboxState.install-method == "flatpak": VerticalLayout { + spacing: 4px; + alignment: start; + + GroupHeader { text: @tr("FLATPAK SANDBOX"); } + RowNote { + text: @tr("QBZ is running inside a Flatpak sandbox. Some features need one-time permission grants — run the commands in a terminal, then restart QBZ. Grants persist across updates."); + } + Rectangle { height: 8px; } + + RowTitle { text: @tr("Exclusive DAC access (bit-perfect)"); } + RowNote { + text: @tr("Recommended for exclusive mode: lets QBZ ask PipeWire to hand over the DAC cleanly (D-Bus device reservation)."); + } + CommandBlock { + command: "flatpak override --user --own-name=org.freedesktop.ReserveDevice1.* com.blitzfc.qbz"; + } + Rectangle { height: 8px; } + + RowTitle { text: @tr("Music on NAS or external drives"); } + RowNote { + text: @tr("Grants access to a folder outside the sandbox. Repeat the command for each folder you need."); + } + CommandBlock { + command: "flatpak override --user --filesystem=/path/to/your/music com.blitzfc.qbz"; + } + } + + // --- SNAP ------------------------------------------------------------ + if SandboxState.install-method == "snap": VerticalLayout { + spacing: 4px; + alignment: start; + + GroupHeader { text: @tr("SNAP SANDBOX"); } + RowNote { + text: @tr("QBZ is running inside a Snap sandbox. Some audio interfaces need one-time connections — run these commands in a terminal, then restart QBZ."); + } + Rectangle { height: 8px; } + + RowTitle { text: @tr("Required audio connections"); } + CommandBlock { + command: "sudo snap connect qbz-player:alsa\nsudo snap connect qbz-player:pulseaudio\nsudo snap connect qbz-player:pipewire\nsudo snap connect qbz-player:mpris"; + } + Rectangle { height: 8px; } + + RowTitle { text: @tr("Optional — external drives & NAS"); } + CommandBlock { + command: "sudo snap connect qbz-player:removable-media"; + } + } +} diff --git a/crates/qbz-ui/ui/settings/SettingsView.slint b/crates/qbz-ui/ui/settings/SettingsView.slint index 739422ddf..07a02c96b 100644 --- a/crates/qbz-ui/ui/settings/SettingsView.slint +++ b/crates/qbz-ui/ui/settings/SettingsView.slint @@ -8,7 +8,7 @@ import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; -import { NavState, ContentView, SettingsState, LogViewerState } from "../state.slint"; +import { NavState, ContentView, SettingsState, LogViewerState, SandboxState } from "../state.slint"; import { QbzIcon } from "../primitives/QbzIcon.slint"; import { NavButtons } from "../shell/NavButtons.slint"; import { AudioSettings } from "AudioSettings.slint"; @@ -19,6 +19,7 @@ import { LocalLibrarySettings } from "LocalLibrarySettings.slint"; import { ContentFilteringSettings } from "ContentFilteringSettings.slint"; import { IntegrationsSettings } from "IntegrationsSettings.slint"; import { DeveloperSettings } from "DeveloperSettings.slint"; +import { SandboxSettings } from "SandboxSettings.slint"; import { ScrollView } from "std-widgets.slint"; import { ListScrollbar } from "../primitives/ListScrollbar.slint"; @@ -180,6 +181,24 @@ export component SettingsView inherits Rectangle { SettingsState.section = 5; } } + // Sandbox (Flatpak/Snap) — only on sandboxed installs; + // holds the one-time permission commands (Tauri parity). + if SandboxState.install-method == "flatpak": SubNavItem { + icon: @image-url("../assets/icons/lock.svg"); + label: @tr("Flatpak"); + active: SettingsState.section == 8; + clicked => { + SettingsState.section = 8; + } + } + if SandboxState.install-method == "snap": SubNavItem { + icon: @image-url("../assets/icons/lock.svg"); + label: @tr("Snap"); + active: SettingsState.section == 8; + clicked => { + SettingsState.section = 8; + } + } // Absorbs the leftover height so the log affordance below // pins to the bottom of the sub-nav column. Rectangle { } @@ -277,6 +296,7 @@ export component SettingsView inherits Rectangle { } } if !SettingsState.loading && SettingsState.section == 5: DeveloperSettings { } + if !SettingsState.loading && SettingsState.section == 8: SandboxSettings { } } } ListScrollbar { diff --git a/crates/qbz-ui/ui/state.slint b/crates/qbz-ui/ui/state.slint index a405fc749..9fe20b8a7 100644 --- a/crates/qbz-ui/ui/state.slint +++ b/crates/qbz-ui/ui/state.slint @@ -5709,6 +5709,19 @@ export global DacWizardActions { callback toggle-config(int); // collapse/expand one DAC's config accordion } +// ============================================================================ +// Sandbox (Flatpak/Snap) — Settings section holding the one-time permission +// commands for sandboxed installs (Tauri parity: Settings > Flatpak / Snap). +// The section is only shown when install-method is "flatpak" or "snap". +// ============================================================================ + +export global SandboxState { + // "flatpak" | "snap" | anything else (section hidden). Seeded once at + // startup from qbz_app::diagnostics::system_info().install_method. + in property install-method: ""; + callback copy-command(string); // → crate::share::copy_to_clipboard +} + // ============================================================================ // Keyboard shortcuts (hotkeys) — port of the Tauri keybindings system. // ============================================================================ diff --git a/crates/qbz/src/main.rs b/crates/qbz/src/main.rs index c420fe1a8..d50f0e09a 100644 --- a/crates/qbz/src/main.rs +++ b/crates/qbz/src/main.rs @@ -20721,6 +20721,19 @@ fn main() -> Result<(), Box> { }); } + // ---- Sandbox (Flatpak/Snap) settings section ---- + // Seed the install method once (drives section visibility) and wire the + // copy-to-clipboard action for the permission commands. + { + let method = qbz_app::diagnostics::system_info().install_method; + window.global::().set_install_method(method.into()); + window + .global::() + .on_copy_command(move |cmd| { + share::copy_to_clipboard(cmd.to_string()); + }); + } + // ---- Playlist Importer (public playlists) — spec §3.3 ---- { // No cancel exists: a running import task continues to completion