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