feat(qt): artist page parity - load more, section sort, discography
The release-section "Load more" fetched a page and appended it to a structure
no view ever re-read. The handler pushed IN PLACE into the object behind
`readonly property var artist: JSON.parse(QbzArtist.artistJson)`, and the
releaseSections projection returned that same array on the unfiltered arm, so
both Repeaters were re-handed the identical reference and nothing was dirty.
The tree's own rule, written in cards/PlaylistCollage.qml: rebind requires a
NEW object reference. A second bug sat on the same path - the artist document
republishes progressively (stories, then each MusicBrainz section as it
resolves) and every republish re-runs the parse, wiping anything appended, so
fixing only the first would have left a bug that looks random. Both
pre-existing; the in-flight placeholder added earlier is what made an
always-silent no-op visible.
Appended pages now live in an overlay keyed by release type. It survives a
republish, emits new arrays so the Repeaters rebuild, dedupes by album id,
carries the reference's 4-page cap per bucket (artist.rs:718-720, which hands
off to the discography page beyond it), and is guarded against a page
requested on one artist landing on another's grid - releaseSectionReady
carries no artist id and every artist has an "album" bucket.
"See discography" was a pointer-cursor MouseArea with no onClicked under a
POC-NOTE saying the page was out of scope. ArtistReleasesView.qml +
artist_releases_qt.rs port ArtistReleasesView.slint: infinite scroll rather
than a button, plus the loading, error-with-retry, empty and offline arms.
The album page's "More from <artist>" view-all is a second door to the same
page. Its paging offset counts what the SERVER returned rather than the
rendered row count the reference uses: blacklist filtering and id dedupe make
the rendered count smaller, so the reference re-requests seen rows and skips
the tail whenever the blacklist is non-empty.
The per-section sort was a dimmed Rectangle with no MouseArea, under a
comment asserting no seam existed. It is now a real QbzSelect with the
reference's five options and index mapping, persisted per release type in
artist_prefs. Choosing "Default" after a sort does not restore the server
order until the page reloads - that is the reference's behaviour
(album_map.rs:262 is a bare no-op arm and resort sorts the live model), kept
deliberately rather than diverged.
Also, two visual fixes from the same round that share these files: Popular
Tracks drew its cover at radius 8 where the shared rows/TrackRow.qml uses 4,
and the album page's rail mounts said `width: parent.width` inside a Column
with 32px padding - QML padding shifts children without narrowing
parent.width, so the rails hung 32px off the right and the right page chevron
landed outside the window.
Carries scripts/qt-diag.sh, which has been sitting untracked since the
rendering round: it answers "which backend is this actually running on" from
a real graphical session, refusing ssh and refusing offscreen because either
would answer the wrong question. That refusal is the point - the doctrine it
disproved ("shader effects render nothing on this port's software path") came
from an offscreen observation, and offscreen forces software by definition.
cc
This commit is contained in:
15 files changed
+2259
-128
No files matched your search
Executable
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
# QBZ Qt — RENDERING DIAGNOSTIC. Launches the app with Qt's scene-graph and RHI
|
||||
# logging on, samples the process's CPU while you drive it, and leaves ONE log
|
||||
# file you can copy off the machine.
|
||||
#
|
||||
# Why this exists: the whole "this port runs on the software renderer" doctrine
|
||||
# — repeated across ~8 QML file headers and used to justify pre-baked icon
|
||||
# tints, Canvas-based rounded covers and a blanket no-effects rule — came from
|
||||
# an observation made OFFSCREEN, and QT_QPA_PLATFORM=offscreen forces software
|
||||
# by definition. On Linux, QSG_INFO in a real window says otherwise: OpenGL RHI,
|
||||
# threaded render loop, Intel Arc. macOS is still unmeasured. So: measure, in a
|
||||
# REAL graphical session, never over ssh and never offscreen.
|
||||
#
|
||||
# WHAT TO DO WHILE IT RUNS (the log is only as good as the session):
|
||||
# 1. Let it sit idle on Home for ~15s.
|
||||
# 2. Play a track. Let it settle ~15s.
|
||||
# 3. Switch the now-playing bar through its modes (New / Classic / Small /
|
||||
# Large), pausing ~15s on each — Large is the one that mounts the FFT
|
||||
# spectrum, which is the suspect.
|
||||
# 4. Hover a few album cards.
|
||||
# 5. Close the app normally. The summary is written on exit.
|
||||
#
|
||||
# Usage: ./scripts/qt-diag.sh # release binary, must already be built
|
||||
# DEBUG=1 ./scripts/qt-diag.sh # debug binary instead
|
||||
# INTERVAL=2 ./scripts/qt-diag.sh # CPU sample period in seconds (default 2)
|
||||
set -uo pipefail
|
||||
cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
|
||||
|
||||
UNAME_S="$(uname -s)"
|
||||
PROFILE=$([[ "${DEBUG:-0}" == 1 ]] && echo debug || echo release)
|
||||
BIN="crates/target/${PROFILE}/qbz-qt"
|
||||
INTERVAL="${INTERVAL:-2}"
|
||||
|
||||
[[ -x "${BIN}" ]] || { echo "[qt-diag] no binary at ${BIN} — build first (./scripts/qt-run.sh NORUN=1)" >&2; exit 1; }
|
||||
|
||||
# Refuse to produce a log that answers the wrong question. Offscreen forces
|
||||
# software, and a headless ssh session has no compositor to talk to — either
|
||||
# would make the backend line meaningless, which is the one line we are here for.
|
||||
if [[ "${QT_QPA_PLATFORM:-}" == offscreen ]]; then
|
||||
echo "[qt-diag] QT_QPA_PLATFORM=offscreen forces the software backend — that is the mistake this script exists to correct. Unset it." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${UNAME_S}" != "Darwin" && -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
|
||||
echo "[qt-diag] no DISPLAY / WAYLAND_DISPLAY — run this from the machine's own graphical session, not over ssh." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
stamp="$(date +%Y%m%d-%H%M%S)"
|
||||
host="$(hostname -s 2>/dev/null || hostname)"
|
||||
LOG="${PWD}/qt-diag-${host}-${stamp}.log"
|
||||
|
||||
{
|
||||
echo "=============================================================="
|
||||
echo " QBZ Qt rendering diagnostic"
|
||||
echo " host : ${host}"
|
||||
echo " when : $(date '+%Y-%m-%d %H:%M:%S %Z')"
|
||||
echo " os : $(uname -srm)"
|
||||
[[ "${UNAME_S}" == "Darwin" ]] && echo " macos : $(sw_vers -productVersion)"
|
||||
echo " binary : ${BIN} ($(date -r "${BIN}" '+%Y-%m-%d %H:%M' 2>/dev/null || stat -c %y "${BIN}" 2>/dev/null))"
|
||||
echo " profile : ${PROFILE}"
|
||||
echo "=============================================================="
|
||||
echo
|
||||
echo "---- display ----"
|
||||
if [[ "${UNAME_S}" == "Darwin" ]]; then
|
||||
system_profiler SPDisplaysDataType 2>/dev/null | grep -iE 'resolution|ui looks like|chipset|vram|metal' || true
|
||||
else
|
||||
xrandr 2>/dev/null | grep -E ' connected|\*' || echo "(xrandr unavailable — wayland?)"
|
||||
echo "session type: ${XDG_SESSION_TYPE:-unknown}"
|
||||
fi
|
||||
echo
|
||||
echo "---- qt ----"
|
||||
(qmake6 -query QT_VERSION 2>/dev/null || /opt/homebrew/opt/qt/bin/qmake -query QT_VERSION 2>/dev/null || echo unknown) | sed 's/^/qt version: /'
|
||||
echo "effects modules present:"
|
||||
for d in /usr/lib64/qt6/qml /usr/lib/qt6/qml /opt/homebrew/share/qt/qml; do
|
||||
[[ -d "$d/QtQuick/Effects" ]] && echo " QtQuick.Effects -> $d"
|
||||
[[ -d "$d/Qt5Compat/GraphicalEffects" ]] && echo " Qt5Compat.GraphicalEffects -> $d"
|
||||
done
|
||||
echo "backend forced by env: QT_QUICK_BACKEND='${QT_QUICK_BACKEND:-}' QSG_RHI_BACKEND='${QSG_RHI_BACKEND:-}' QSG_RENDER_LOOP='${QSG_RENDER_LOOP:-}'"
|
||||
echo
|
||||
echo "---- app log (QSG_INFO + scenegraph/rhi categories) ----"
|
||||
} > "${LOG}"
|
||||
|
||||
echo "[qt-diag] log -> ${LOG}"
|
||||
echo "[qt-diag] drive the app as described in this script's header, then close it normally."
|
||||
|
||||
# The two lines that answer the question are 'Creating QRhi with backend X' and
|
||||
# 'Prefer software device: N'. The rhi/scenegraph categories carry them.
|
||||
QSG_INFO=1 \
|
||||
QT_LOGGING_RULES="qt.scenegraph.general=true;qt.rhi.general=true" \
|
||||
"./${BIN}" >> "${LOG}" 2>&1 &
|
||||
app_pid=$!
|
||||
|
||||
# CPU sampler. ps reports a per-process percentage on both platforms; on macOS
|
||||
# it is a share of ONE core (so >100 is possible), same as Linux.
|
||||
samples="$(mktemp)"
|
||||
(
|
||||
while kill -0 "${app_pid}" 2>/dev/null; do
|
||||
cpu=$(ps -o %cpu= -p "${app_pid}" 2>/dev/null | tr -d ' ')
|
||||
rss=$(ps -o rss= -p "${app_pid}" 2>/dev/null | tr -d ' ')
|
||||
[[ -n "${cpu}" ]] && printf '%s %s %s\n' "$(date '+%H:%M:%S')" "${cpu}" "${rss:-0}" >> "${samples}"
|
||||
sleep "${INTERVAL}"
|
||||
done
|
||||
) &
|
||||
sampler=$!
|
||||
|
||||
trap 'kill "${app_pid}" 2>/dev/null || true' INT TERM
|
||||
wait "${app_pid}" 2>/dev/null
|
||||
kill "${sampler}" 2>/dev/null || true
|
||||
wait "${sampler}" 2>/dev/null || true
|
||||
|
||||
{
|
||||
echo
|
||||
echo "---- cpu samples (time, %cpu of one core, rss KB) ----"
|
||||
cat "${samples}" 2>/dev/null
|
||||
echo
|
||||
echo "---- cpu summary ----"
|
||||
awk '{n++; s+=$2; if($2>mx)mx=$2; if(n==1||$2<mn)mn=$2}
|
||||
END{ if(n) printf "samples=%d min=%.1f%% avg=%.1f%% max=%.1f%%\n", n, mn, s/n, mx;
|
||||
else print "(no samples — the process exited immediately)" }' "${samples}" 2>/dev/null
|
||||
echo
|
||||
echo "---- what to look for ----"
|
||||
echo " * 'Creating QRhi with backend <X>' -> OpenGL/Metal/Vulkan = GPU; 'software' = not."
|
||||
echo " * 'Prefer software device: 1' -> something asked for software explicitly."
|
||||
echo " * 'Animation Driver: using vsync' -> ms per frame; 5.56 = 180Hz, 10.0 = 100Hz."
|
||||
echo " * a max% that tracks the NPB Large window is the FFT spectrum band."
|
||||
} >> "${LOG}"
|
||||
rm -f "${samples}"
|
||||
|
||||
echo
|
||||
echo "[qt-diag] done. Backend line:"
|
||||
grep -aE 'Creating QRhi|Prefer software|using vsync' "${LOG}" | sed 's/^/ /' || echo " (none found — did the window open?)"
|
||||
echo "[qt-diag] full log: ${LOG}"
|
||||
Reference in new issue
Block a user