Initial implementation of qobuz-qt

- Rust backend (qobuz-backend static lib): Qobuz API client (reqwest/tokio),
  Symphonia audio decoder, CPAL audio output, extern "C" FFI bridge
- Qt 6 frontend mirroring spotify-qt layout: toolbar with playback controls,
  left library dock, central track list, right search panel
- Auth: email/password login with MD5-signed requests; session token persisted
  via QSettings
- Playback: double-click a track → Rust fetches stream URL → Symphonia decodes
  → CPAL outputs to default audio device
- Dark Fusion palette matching spotify-qt feel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
joren
2026-03-23 23:34:23 +01:00
commit 9402dca7ed
40 changed files with 3963 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
#pragma once
#include "clickableslider.hpp"
#include "../util/icon.hpp"
#include <QToolButton>
#include <QWidgetAction>
#include <QMenu>
#include <QLabel>
#include <QVBoxLayout>
/// A toolbar button that shows a volume slider popup when clicked.
class VolumeButton : public QToolButton
{
Q_OBJECT
public:
explicit VolumeButton(QWidget *parent = nullptr) : QToolButton(parent)
{
setPopupMode(QToolButton::InstantPopup);
setIcon(Icon::volumeHigh());
auto *menu = new QMenu(this);
auto *widget = new QWidget(menu);
auto *layout = new QVBoxLayout(widget);
layout->setContentsMargins(6, 6, 6, 6);
m_label = new QLabel("80%", widget);
m_label->setAlignment(Qt::AlignCenter);
m_slider = new ClickableSlider(Qt::Vertical, widget);
m_slider->setRange(0, 100);
m_slider->setValue(80);
m_slider->setFixedHeight(120);
layout->addWidget(m_label);
layout->addWidget(m_slider);
auto *action = new QWidgetAction(menu);
action->setDefaultWidget(widget);
menu->addAction(action);
setMenu(menu);
connect(m_slider, &QSlider::valueChanged, this, [this](int v) {
m_label->setText(QString::number(v) + "%");
updateIcon(v);
emit volumeChanged(v);
});
}
int value() const { return m_slider->value(); }
void setValue(int v)
{
m_slider->blockSignals(true);
m_slider->setValue(v);
m_slider->blockSignals(false);
m_label->setText(QString::number(v) + "%");
updateIcon(v);
}
signals:
void volumeChanged(int volume);
private:
ClickableSlider *m_slider = nullptr;
QLabel *m_label = nullptr;
void updateIcon(int v)
{
if (v == 0) setIcon(Icon::volumeMute());
else if (v < 50) setIcon(Icon::volumeMid());
else setIcon(Icon::volumeHigh());
}
};