feat: initial qobuz-qt source

Lightweight Qt6 desktop client for Qobuz with a Rust audio backend
(Symphonia/CPAL via staticlib FFI). Mirrors the spotify-qt layout:
toolbar with playback controls, library/context docks on the left,
tabbed search side panel on the right, queue panel, now-playing dock.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
joren
2026-03-24 00:41:04 +01:00
parent 35ae649fc9
commit cb2323bc32
85 changed files with 4484 additions and 249 deletions

View File

@@ -1,32 +1,46 @@
#pragma once
#include <QFile>
#include <QIcon>
#include <QString>
namespace Icon
{
/// Load an icon by name. Checks the embedded :/res/icons/ first, then
/// falls back to the system theme. The dark SVGs from spotify-qt are
/// bundled so this always succeeds for known names.
inline QIcon get(const QString &name)
{
// Try theme icon first, fall back to resource
if (QIcon::hasThemeIcon(name))
return QIcon::fromTheme(name);
return QIcon(QStringLiteral(":/icons/%1.svg").arg(name));
const QString path = QStringLiteral(":/res/icons/%1.svg").arg(name);
if (QFile::exists(path))
return QIcon(path);
return QIcon::fromTheme(name);
}
// Convenient aliases for common icons used throughout the app
// Playback
inline QIcon play() { return get("media-playback-start"); }
inline QIcon pause() { return get("media-playback-pause"); }
inline QIcon stop() { return get("media-playback-stop"); }
inline QIcon next() { return get("media-skip-forward"); }
inline QIcon previous() { return get("media-skip-backward"); }
inline QIcon shuffle() { return get("media-playlist-shuffle"); }
inline QIcon repeat() { return get("media-playlist-repeat"); }
// Volume
inline QIcon volumeHigh() { return get("audio-volume-high"); }
inline QIcon volumeMid() { return get("audio-volume-medium"); }
inline QIcon volumeMute() { return get("audio-volume-muted"); }
inline QIcon volumeLow() { return get("audio-volume-low"); }
inline QIcon volumeMute() { return get("audio-volume-low"); }
// UI
inline QIcon search() { return get("edit-find"); }
inline QIcon heart() { return get("emblem-favorite"); }
inline QIcon album() { return get("media-optical"); }
inline QIcon artist() { return get("system-users"); }
inline QIcon playlist() { return get("view-list-symbolic"); }
inline QIcon heart() { return get("starred-symbolic"); }
inline QIcon heartOff() { return get("non-starred-symbolic"); }
inline QIcon album() { return get("view-media-album-cover"); }
inline QIcon artist() { return get("view-media-artist"); }
inline QIcon playlist() { return get("view-media-playlist"); }
inline QIcon track() { return get("view-media-track"); }
inline QIcon queue() { return get("media-playlist-append"); }
inline QIcon refresh() { return get("view-refresh"); }
inline QIcon settings() { return get("configure"); }
inline QIcon sortAsc() { return get("view-sort-ascending"); }
}