Files
qbz/crates/qbz-qt/qml/kiosk/KioskEmptyState.qml
T
vicrodh b1dba198c9 feat(qt): kiosk profile release hardening
Integrate the Kiosk profile hardening round: 12 dedicated Kiosk views plus
22 shared opt-in hosts, shared navigation history with Back/Forward, Albums
as the default library tab, native paged Local Library (artists/tracks),
lightweight MyQBZ grid and detail, Ephemeral lifecycle, bounded lists and
artwork sized to the physical frame, static skeletons, 64px transport bar,
Settings touch reflow and a persistent Immersive exit.

Desktop keeps its prior behavior: every shared component defaults to the
desktop path and only opts into Kiosk behavior through explicit properties
(origin-relative ScrollMemory, viewport-bounded artwork requests).

Regression coverage: kiosk navigation and artwork Node tests added to the
runtime gate, scroll-origin fixtures for fixed and grouped rows, i18n
strings for all eight locales.

Verified by 750 release tests, six QML audits, Kiosk smokes at 800x480 and
1280x800 and a Desktop A/B with seven pixel-identical captures.

cc
2026-09-07 08:23:11 -06:00

79 lines
2.9 KiB
QML

// KioskEmptyState — the static "there is nothing here" / "this failed" panel
// of the kiosk shell.
//
// Contract §1.7: a kiosk route must let the user tell loading, empty, error and
// populated apart without looking dead. This is the second and third of those
// four; KioskSkeleton is the first, and it is what mounts this file.
//
// DELIBERATELY INERT. No icon, no artwork, no button, no animation, no timer.
// - no artwork, because an empty state that mounts an image is a network
// request for a state that by definition has no content (contract §5.2:
// "un tab/card no montado no solicita imagen");
// - no action, because the RETRY lives with whoever owns the document. This
// panel is presentational; a host that wants a retry puts its own control
// under it and gets the ≥64 px target from its own chrome.
//
// TEXT IS SUPPLIED, NOT INVENTED. `text` and `detail` arrive already
// translated from the host (KioskSkeleton passes an existing msgid through
// QbzSession.tr, and an error string arrives from the document that produced
// it). Nothing here hardcodes English.
//
// Sizing is for the 800x480 floor: the label wraps, is capped at four lines and
// elides, and the whole block stays inside the item, so a long German or
// Russian string cannot push itself off a Pi panel.
import QtQuick
import "../theme"
Item {
id: root
/// The headline. Already translated.
property string text: ""
/// An optional second line — a document's own error detail, a hint. Already
/// translated. Empty hides it.
property string detail: ""
/// Error tone: the headline takes the secondary text colour instead of the
/// muted one, so a failure reads louder than an emptiness without
/// introducing a red the kiosk theme does not define.
property bool isError: false
/// Horizontal breathing room. 24 keeps the block clear of the NavRail at
/// 800 px wide.
property real pad: 24
QbzTheme { id: theme }
implicitHeight: block.implicitHeight
Column {
id: block
anchors.centerIn: parent
width: Math.max(0, root.width - 2 * root.pad)
spacing: 8
Text {
width: block.width
text: root.text
color: root.isError ? theme.textSecondary : theme.textMuted
font.pixelSize: 16
font.weight: theme.weightMedium
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
maximumLineCount: 3
elide: Text.ElideRight
}
Text {
width: block.width
visible: root.detail !== ""
text: root.detail
color: theme.textMuted
font.pixelSize: 13
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
maximumLineCount: 4
elide: Text.ElideRight
}
}
}