Merge branch 'feature/internal/lyrics-translation' into chore/internal/smoke-lyrics-discover
This commit is contained in:
4 files changed
+39
-57
No files matched your search
@@ -1,20 +0,0 @@
|
||||
<!-- @license lucide-static v1.17.0 - ISC -->
|
||||
<svg
|
||||
class="lucide lucide-languages"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m5 8 6 6" />
|
||||
<path d="m4 14 6-6 2-3" />
|
||||
<path d="M2 5h12" />
|
||||
<path d="M7 2h1" />
|
||||
<path d="m22 22-5-10-5 10" />
|
||||
<path d="M14 18h6" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 437 B |
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.93 2H5.02C3 2 2 3 2 5.02V8.94C2 11 3 12 5.02 11.95H8.94C11 12 12 11 11.95 8.93V5.02C12 3 11 2 8.93 2ZM9.01 9.76C8.33 9.76 7.67 9.5 7.12 9.04C6.5 9.49 5.75 9.76 4.94 9.76C4.53 9.76 4.19 9.42 4.19 9.01C4.19 8.6 4.53 8.26 4.94 8.26C5.96 8.26 6.81 7.56 7.12 6.6H4.94C4.53 6.6 4.19 6.26 4.19 5.85C4.19 5.44 4.53 5.1 4.94 5.1H6.23C6.27 4.72 6.58 4.42 6.97 4.42C7.36 4.42 7.67 4.72 7.71 5.1H7.97C7.98 5.1 7.99 5.1 7.99 5.1H8.01H9C9.41 5.1 9.75 5.44 9.75 5.85C9.75 6.26 9.42 6.6 9 6.6H8.67C8.58 7.08 8.39 7.53 8.14 7.94C8.41 8.14 8.7 8.26 9.01 8.26C9.42 8.26 9.76 8.6 9.76 9.01C9.76 9.42 9.42 9.76 9.01 9.76Z" fill="#292D32"/>
|
||||
<path d="M9 22.75C4.73 22.75 1.25 19.27 1.25 15C1.25 14.59 1.59 14.25 2 14.25C2.41 14.25 2.75 14.59 2.75 15C2.75 17.96 4.81 20.44 7.58 21.09L7.31 20.64C7.1 20.28 7.21 19.82 7.57 19.61C7.92 19.4 8.39 19.51 8.6 19.87L9.65 21.62C9.79 21.85 9.79 22.14 9.66 22.37C9.52 22.6 9.27 22.75 9 22.75Z" fill="#292D32"/>
|
||||
<path d="M21.9985 9.75C21.5885 9.75 21.2485 9.41 21.2485 9C21.2485 6.04 19.1885 3.56 16.4185 2.91L16.6885 3.36C16.8985 3.72 16.7885 4.18 16.4285 4.39C16.0785 4.6 15.6085 4.49 15.3985 4.13L14.3485 2.38C14.2085 2.15 14.2085 1.86 14.3385 1.63C14.4785 1.4 14.7285 1.25 14.9985 1.25C19.2685 1.25 22.7485 4.73 22.7485 9C22.7485 9.41 22.4085 9.75 21.9985 9.75Z" fill="#292D32"/>
|
||||
<path d="M16.9198 11.8516C14.1198 11.8516 11.8398 14.1216 11.8398 16.9316C11.8398 19.7316 14.1098 22.0116 16.9198 22.0116C19.7198 22.0116 21.9998 19.7416 21.9998 16.9316C21.9998 14.1216 19.7298 11.8516 16.9198 11.8516ZM19.3998 19.3416C19.0298 19.5216 18.5798 19.3816 18.3898 19.0016L18.2198 18.6616H15.6298L15.4598 19.0016C15.3298 19.2616 15.0598 19.4116 14.7898 19.4116C14.6798 19.4116 14.5598 19.3816 14.4598 19.3316C14.0898 19.1416 13.9398 18.6916 14.1198 18.3216L16.2598 14.0516C16.3898 13.8016 16.6498 13.6416 16.9298 13.6416C17.2098 13.6416 17.4698 13.8016 17.5998 14.0616L19.7398 18.3316C19.9198 18.7016 19.7698 19.1516 19.3998 19.3416Z" fill="#292D32"/>
|
||||
<path d="M16.3789 17.1603H17.4689L16.9189 16.0703L16.3789 17.1603Z" fill="#292D32"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -25,32 +25,26 @@ import { LyricsLinesView } from "LyricsLinesView.slint";
|
||||
import { LyricsControlsPanel } from "LyricsControlsFlyout.slint";
|
||||
import { ShellState, LyricsState, ArtworkActions, AppearanceState, TooltipState } from "../state.slint";
|
||||
|
||||
// Floating translate toggle (Qobuz v10, owner decision 2026-07-22): circular
|
||||
// button anchored bottom-right of the lyrics body, overlaying it — mobile
|
||||
// parity (the 文A button on iOS/Android). Off = dim, on = accent. Tooltip
|
||||
// rides the shared TooltipState channel like the bar's IconButton.
|
||||
// Floating translate toggle (Qobuz v10, owner decisions 2026-07-22/23):
|
||||
// square ghost button anchored bottom-right of the lyrics body, overlaying
|
||||
// it. Styled after the Discover configurator gear (GearButton in
|
||||
// HomeView.slint): no border, bg lights up on hover; the accent tint is the
|
||||
// ON state. Tooltip rides the shared TooltipState channel.
|
||||
component TranslateButton inherits Rectangle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 18px;
|
||||
background: LyricsState.show-translation
|
||||
? Theme.accent.with-alpha(0.15)
|
||||
: Theme.surface-card;
|
||||
border-width: 1px;
|
||||
border-color: LyricsState.show-translation ? Theme.accent : Theme.border-muted;
|
||||
drop-shadow-blur: 12px;
|
||||
drop-shadow-color: Theme.card-shadow;
|
||||
drop-shadow-offset-y: 3px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
background: ta.has-hover ? Theme.surface-hover : transparent;
|
||||
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/languages.svg");
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
source: @image-url("../assets/icons/translate.svg");
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
x: Math.round((parent.width - self.width) / 2 / 1px) * 1px;
|
||||
y: Math.round((parent.height - self.height) / 2 / 1px) * 1px;
|
||||
tint: LyricsState.show-translation
|
||||
? Theme.accent
|
||||
: (ta.has-hover ? Theme.text-primary : Theme.text-secondary);
|
||||
: (ta.has-hover ? Theme.text-primary : Theme.text-muted);
|
||||
}
|
||||
|
||||
ta := TouchArea {
|
||||
|
||||
+18
-18
@@ -39,8 +39,9 @@
|
||||
//! [`enable_translation`] and flips `show-translation` only when a
|
||||
//! translation actually arrived — any gap toasts and reverts (fail soft,
|
||||
//! never an error state). Toggling OFF ([`disable_translation`]) is pure
|
||||
//! UI. While ON, track-change requests ride the resolved target so the
|
||||
//! translation follows across tracks.
|
||||
//! UI. The toggle is PER-TRACK (owner decision 2026-07-23): it applies
|
||||
//! only to the song it was enabled on — every track change resets it and
|
||||
//! fetches original-only.
|
||||
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
|
||||
@@ -287,8 +288,8 @@ pub fn clear_cache(handle: &tokio::runtime::Handle, weak: slint::Weak<AppWindow>
|
||||
|
||||
/// Whether the translation toggle is currently ON (Rust-side source of truth
|
||||
/// behind `LyricsState.show-translation`). main.rs reads it to route the
|
||||
/// toggle callback; the fetch path reads [`active_translation_language`] to
|
||||
/// keep requesting the target across track changes.
|
||||
/// toggle callback. Per-track (owner 2026-07-23): reset on every track
|
||||
/// change in [`on_track_changed`].
|
||||
pub fn translation_enabled() -> bool {
|
||||
TRANSLATION.lock().map(|t| t.enabled).unwrap_or(false)
|
||||
}
|
||||
@@ -300,15 +301,6 @@ fn reset_translation_session() {
|
||||
}
|
||||
}
|
||||
|
||||
/// The target the toggle was enabled with, while ON — the track-change fetch
|
||||
/// rides it so the translation follows across tracks (spec §B).
|
||||
fn active_translation_language() -> Option<String> {
|
||||
TRANSLATION
|
||||
.lock()
|
||||
.ok()
|
||||
.and_then(|t| t.enabled.then(|| t.language.clone()).flatten())
|
||||
}
|
||||
|
||||
/// Account language (ISO 639-1) from the shared client's session — the
|
||||
/// "Auto" resolution's first hop. None pre-login / pre-v10 sessions.
|
||||
async fn account_language() -> Option<String> {
|
||||
@@ -538,6 +530,11 @@ pub fn on_track_changed(weak: slint::Weak<AppWindow>, track: &QueueTrack) {
|
||||
return;
|
||||
};
|
||||
|
||||
// Per-track translation toggle (owner 2026-07-23): a new track always
|
||||
// starts original-only — any translation the user enabled was for the
|
||||
// PREVIOUS song only.
|
||||
reset_translation_session();
|
||||
|
||||
let source = source_kind(track);
|
||||
// F4 contract, explicit: the RAW title goes to the engine (fallback
|
||||
// providers match on the unversioned title; Qobuz looks up by id). The
|
||||
@@ -557,10 +554,11 @@ pub fn on_track_changed(weak: slint::Weak<AppWindow>, track: &QueueTrack) {
|
||||
// Offline as data, not lookup (spec §2.2.4): the engine verdict is
|
||||
// read here and travels with the request.
|
||||
offline: crate::offline_mode::engine().is_offline(),
|
||||
// Default flow fetches original-only (spec §B.1). While the
|
||||
// translation toggle is ON the request rides the resolved target so
|
||||
// the translation follows across tracks.
|
||||
language: active_translation_language(),
|
||||
// Default flow always fetches original-only (spec §B.1): the
|
||||
// translation toggle is per-track (owner 2026-07-23) and was reset
|
||||
// above; enabling it refetches WITH a language via
|
||||
// [`enable_translation`].
|
||||
language: None,
|
||||
};
|
||||
let key = request_identity(
|
||||
request.track_id,
|
||||
@@ -602,8 +600,10 @@ pub fn on_track_changed(weak: slint::Weak<AppWindow>, track: &QueueTrack) {
|
||||
state.set_provider_label("".into());
|
||||
state.set_error("".into());
|
||||
// Hide the toggle while loading — the availability of the NEXT
|
||||
// track's doc is unknown until its commit.
|
||||
// track's doc is unknown until its commit. The toggle itself is
|
||||
// per-track: it always starts OFF for a new track.
|
||||
state.set_translation_available(false);
|
||||
state.set_show_translation(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user