Mostly reimplement Player, begin implementing ViewPlayer UI design
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -85,6 +85,7 @@ CMakeLists.txt.user*
|
||||
.vs/
|
||||
out/
|
||||
|
||||
.cache
|
||||
.direnv
|
||||
dist
|
||||
CMakePresets.json
|
||||
|
||||
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"C_Cpp.workspaceParsingPriority": "medium",
|
||||
"files.associations": {
|
||||
"flake.lock": "json",
|
||||
"qobject": "cpp",
|
||||
|
||||
56
Main.qml
56
Main.qml
@@ -11,6 +11,10 @@ ApplicationWindow {
|
||||
height: 800
|
||||
title: qsTr("QYouRadio")
|
||||
|
||||
Component.onCompleted: function() {
|
||||
console.log(Player.stations)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -45,21 +49,21 @@ ApplicationWindow {
|
||||
clip: true
|
||||
|
||||
NumberAnimation {
|
||||
running: Player.currentIndex != null
|
||||
running: Player.playing && tabbar.currentIndex != Player.currentIndex && nowplaying_root.anchors.bottomMargin >= 42
|
||||
target: nowplaying_root
|
||||
property: "anchors.bottomMargin"
|
||||
from: 42
|
||||
to: 0
|
||||
duration: 160
|
||||
duration: 145
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
running: Player.currentIndex == null
|
||||
running: !Player.playing || (tabbar.currentIndex == Player.currentIndex && nowplaying_root.anchors.bottomMargin < 42)
|
||||
target: nowplaying_root
|
||||
property: "anchors.bottomMargin"
|
||||
from: 0
|
||||
to: 42
|
||||
duration: 160
|
||||
duration: 145
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -69,7 +73,7 @@ ApplicationWindow {
|
||||
anchors.topMargin: 1
|
||||
anchors.leftMargin: 4
|
||||
anchors.rightMargin: 4
|
||||
text: (Player.loading ? "Loading " : "Playing ") + (Player.currentIndex != null ? qsTr(Player.currentStream.name) : "")
|
||||
text: (Player.loading ? "Loading " : "Playing ") + qsTr(Player.currentStation.name)
|
||||
heading: "h5"
|
||||
}
|
||||
|
||||
@@ -81,7 +85,7 @@ ApplicationWindow {
|
||||
anchors.bottomMargin: 1
|
||||
anchors.leftMargin: 4
|
||||
// anchors.rightMargin: 4
|
||||
text: (Player.currentIndex != null ? qsTr(Player.currentStream.title) : "")
|
||||
text: qsTr(Player.currentStation.songTitle)
|
||||
heading: "h3"
|
||||
|
||||
|
||||
@@ -124,7 +128,6 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SwipeView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
@@ -134,7 +137,8 @@ ApplicationWindow {
|
||||
currentIndex: tabbar.currentIndex
|
||||
|
||||
Loader {
|
||||
active: tabbar.currentIndex == 0
|
||||
// active: tabbar.currentIndex == 0
|
||||
active: true
|
||||
asynchronous: true
|
||||
visible: status == Loader.Ready
|
||||
sourceComponent: ViewPlayer {
|
||||
@@ -142,7 +146,8 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
active: tabbar.currentIndex == 1
|
||||
// active: tabbar.currentIndex == 1
|
||||
active: true
|
||||
asynchronous: true
|
||||
visible: status == Loader.Ready
|
||||
sourceComponent: ViewPlayer {
|
||||
@@ -150,18 +155,47 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
active: tabbar.currentIndex == 2
|
||||
// active: tabbar.currentIndex == 2
|
||||
active: true
|
||||
asynchronous: true
|
||||
visible: status == Loader.Ready
|
||||
sourceComponent: ViewPlayer {
|
||||
index: 2
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: contentItem.highlightMoveDuration = 160;
|
||||
}
|
||||
|
||||
YouAds {
|
||||
RowLayout {
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 30
|
||||
Layout.bottomMargin: 30
|
||||
width: 220
|
||||
|
||||
Button {
|
||||
Layout.rightMargin: 5
|
||||
text: Player.loading ? "Loading" : (Player.playing ? "Pause" : "Play")
|
||||
|
||||
onClicked: function() {
|
||||
if (Player.playing) {
|
||||
Player.stopPlaying();
|
||||
} else {
|
||||
Player.startPlaying(tabbar.currentIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 5
|
||||
from: 0.1
|
||||
to: 1.1
|
||||
stepSize: 0.05
|
||||
value: Player.volume + 0.1
|
||||
onMoved: Player.volume = value - 0.1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import QtQuick.Layouts 6.8
|
||||
import QYRComponents 1.0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
property var index: null
|
||||
@@ -13,62 +12,40 @@ ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 20
|
||||
text: index != null ? Player.streams[index].name : "Invalid station"
|
||||
text: qsTr(Player.stations[index].name)
|
||||
font.bold: true
|
||||
heading: "h2"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Title: " + (index != null ? Player.streams[index].title : "")
|
||||
heading: "h3"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Listeners: " + (index != null ? Player.streams[index].listeners : 0)
|
||||
heading: "h3"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.topMargin: 20
|
||||
text: (Player.currentIndex != null && Player.currentIndex != parent.index) ? qsTr("Another station is currently playing") : ""
|
||||
heading: "h2"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
width: 220
|
||||
|
||||
Button {
|
||||
Layout.rightMargin: 5
|
||||
text: Player.loading ? "Loading" : (Player.playing ? "Pause" : "Play")
|
||||
|
||||
onClicked: function() {
|
||||
if (Player.playing) {
|
||||
Player.stopPlaying();
|
||||
} else {
|
||||
Player.startPlaying(parent.parent.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 5
|
||||
from: 0.1
|
||||
to: 1.1
|
||||
stepSize: 0.05
|
||||
value: Player.volume + 0.1
|
||||
onMoved: Player.volume = value - 0.1
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: Player.stations[index].songTitle
|
||||
font.pixelSize: 72
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Listening: " + Player.stations[index].listeners
|
||||
heading: "h2"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
visible: (Player.currentIndex > -1 && Player.currentIndex != parent.index)
|
||||
text: qsTr("Another station is currently playing")
|
||||
heading: "h2"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
53
player.cpp
53
player.cpp
@@ -2,8 +2,11 @@
|
||||
|
||||
// Public
|
||||
Player::Player(QObject *parent) : QObject(parent),
|
||||
player(this),
|
||||
output(this)
|
||||
player(this), output(this), timer(this), m_currentIndex(0), m_stations({
|
||||
Station{"Autoradio", "autoradio", "", 0},
|
||||
Station{"Live Mix", "live", "", 0},
|
||||
Station{"Bass Boosted", "bassboosted", "", 0}
|
||||
})
|
||||
{
|
||||
QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () {
|
||||
qDebug("Player::Player()->Lambda: Playing got changed!");
|
||||
@@ -15,7 +18,17 @@ Player::Player(QObject *parent) : QObject(parent),
|
||||
emit this->volumeChanged();
|
||||
});
|
||||
|
||||
this->output.setVolume(0.3);
|
||||
this->timer.start(metadataFetchTimeout);
|
||||
QObject::connect(&this->timer, &QTimer::timeout, this, [this] () {
|
||||
qDebug("Player::Player()->Lambda: Timer triggered!");
|
||||
if (this->m_currentIndex > -1)
|
||||
{
|
||||
emit this->currentStationChanged();
|
||||
}
|
||||
emit this->stationsChanged();
|
||||
});
|
||||
|
||||
this->output.setVolume(0.2);
|
||||
this->player.setAudioOutput(&this->output);
|
||||
|
||||
qDebug("Player::Player(): Constructed");
|
||||
@@ -42,11 +55,30 @@ void Player::setVolume(float newVolume)
|
||||
this->output.setVolume(newVolume);
|
||||
}
|
||||
|
||||
const QList<Station> Player::stations() const
|
||||
{
|
||||
return this->m_stations;
|
||||
}
|
||||
|
||||
const int Player::currentIndex() const
|
||||
{
|
||||
return this->m_currentIndex;
|
||||
}
|
||||
|
||||
const Station* Player::currentStation() const
|
||||
{
|
||||
if (this->m_currentIndex < 0 || this->m_currentIndex >= this->m_stations.length())
|
||||
{
|
||||
qWarning("Player::currentStation(): Tried accessing out of bounds.");
|
||||
return nullptr;
|
||||
}
|
||||
return &this->m_stations[this->m_currentIndex];
|
||||
}
|
||||
|
||||
// Public slots
|
||||
void Player::startPlaying(u_int8_t index)
|
||||
{
|
||||
if (index < 0 || index >= maxStations)
|
||||
if (index < 0 || index >= this->m_stations.length())
|
||||
{
|
||||
qWarning("Player::startPlaying(): Tried accessing out of bounds.");
|
||||
return;
|
||||
@@ -54,19 +86,28 @@ void Player::startPlaying(u_int8_t index)
|
||||
if (this->playing()) {
|
||||
this->stopPlaying();
|
||||
}
|
||||
this->player.setSource(QUrl(streamPrefix + stations[index].slug));
|
||||
this->m_currentIndex = index;
|
||||
emit this->currentIndexChanged();
|
||||
emit this->currentStationChanged();
|
||||
|
||||
this->player.setSource(QUrl("https://youradio.nonamesoft.xyz/youradio/api/" + this->m_stations[index].m_slug));
|
||||
this->player.play();
|
||||
qDebug("Player::startPlaying(): Starting playing");
|
||||
}
|
||||
|
||||
void Player::stopPlaying()
|
||||
{
|
||||
if (this->playing())
|
||||
if (!this->playing())
|
||||
{
|
||||
qWarning("Player::stopPlaying(): Prevented redundant stopPlaying() call.");
|
||||
return;
|
||||
}
|
||||
this->player.stop();
|
||||
this->player.setSource(QUrl(""));
|
||||
|
||||
this->m_currentIndex = -1;
|
||||
emit this->currentIndexChanged();
|
||||
emit this->currentStationChanged();
|
||||
|
||||
qDebug("Player::stopPlaying(): Stopping playback...");
|
||||
}
|
||||
44
player.h
44
player.h
@@ -3,25 +3,27 @@
|
||||
#include <QtMultimedia>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QtQmlIntegration/qqmlintegration.h>
|
||||
|
||||
constexpr int metadataFetchTimeout = 10000;
|
||||
constexpr std::string_view metadataEndpoint = "https://youradio.nonamesoft.xyz/youradio/api/status-json.xsl";
|
||||
constexpr std::string_view streamPrefix = "https://youradio.nonamesoft.xyz/youradio/api/";
|
||||
|
||||
struct Station
|
||||
{
|
||||
const char name[16];
|
||||
const char slug[16];
|
||||
QString* songTitle;
|
||||
u_int8_t listeners;
|
||||
};
|
||||
Q_GADGET
|
||||
|
||||
constexpr u_int8_t maxStations = 3;
|
||||
Q_PROPERTY(QString name MEMBER m_name);
|
||||
Q_PROPERTY(QString slug MEMBER m_slug);
|
||||
Q_PROPERTY(QString songTitle MEMBER m_songTitle);
|
||||
Q_PROPERTY(int listeners MEMBER m_listeners);
|
||||
|
||||
const Station stations[maxStations] = {
|
||||
{ "Autoradio", "autoradio" , nullptr, 0 },
|
||||
{ "Live Mix", "livemix" , nullptr, 0 },
|
||||
{ "Deep Bass", "bassboosted", nullptr, 0 }
|
||||
public:
|
||||
QString m_name;
|
||||
QString m_slug;
|
||||
QString m_songTitle;
|
||||
int m_listeners;
|
||||
};
|
||||
|
||||
class Player : public QObject
|
||||
@@ -30,17 +32,26 @@ class Player : public QObject
|
||||
QML_SINGLETON
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(bool playing READ playing NOTIFY playingChanged)
|
||||
Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
Q_PROPERTY(bool playing READ playing NOTIFY playingChanged FINAL)
|
||||
Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged FINAL)
|
||||
Q_PROPERTY(const QList<Station> stations READ stations NOTIFY stationsChanged FINAL)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged FINAL)
|
||||
Q_PROPERTY(const Station* currentStation READ currentStation NOTIFY currentStationChanged FINAL)
|
||||
|
||||
public:
|
||||
Player(QObject *parent = nullptr);
|
||||
~Player();
|
||||
|
||||
bool playing() const;
|
||||
|
||||
float volume() const;
|
||||
void setVolume(float newVolume);
|
||||
|
||||
const QList<Station> stations() const;
|
||||
|
||||
const int currentIndex() const;
|
||||
const Station* currentStation() const;
|
||||
|
||||
public slots:
|
||||
void startPlaying(u_int8_t index);
|
||||
void stopPlaying();
|
||||
@@ -48,8 +59,15 @@ public slots:
|
||||
signals:
|
||||
void playingChanged();
|
||||
void volumeChanged();
|
||||
void stationsChanged();
|
||||
void currentIndexChanged();
|
||||
void currentStationChanged();
|
||||
|
||||
private:
|
||||
QMediaPlayer player;
|
||||
QAudioOutput output;
|
||||
QTimer timer;
|
||||
|
||||
int m_currentIndex;
|
||||
QList<Station> m_stations;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user