Begin implementing UI design, implement metadata fetching
Some checks failed
Build / build-linux (push) Failing after 17s
Build / build-windows (push) Has been cancelled

This commit is contained in:
Dark Steveneq
2025-10-14 21:02:58 +02:00
parent d46d37c465
commit 18ad69ba5d
4 changed files with 165 additions and 92 deletions

136
Main.qml
View File

@@ -13,80 +13,96 @@ ApplicationWindow {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 10
RowLayout { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
height: 43
Label { color: Colors.surface0
text: "QYouRadio"
heading: "h3"
font.bold: true
}
// Item { RowLayout {
// Layout.fillWidth: true anchors.fill: parent
// } anchors.margins: 3
Rectangle {
Layout.leftMargin: 20
visible: Player.currentIndex != null
color: Colors.primary
radius: 5
clip: true
width: 320
height: 36
Label { Label {
anchors.top: parent.top Layout.leftMargin: 5
anchors.left: parent.left text: "QYouRadio"
anchors.right: parent.right heading: "h1"
anchors.topMargin: 1 // font.bold: true
anchors.leftMargin: 4
anchors.rightMargin: 4
text: (Player.loading ? "Loading " : "Playing ") + (Player.currentIndex != null ? qsTr(Player.currentStream.name) : "")
heading: "h2"
} }
Label { Rectangle {
anchors.bottom: parent.bottom Layout.leftMargin: 5
anchors.left: parent.left visible: Player.currentIndex != null
anchors.right: parent.right color: Colors.primary
anchors.bottomMargin: 1 radius: 5
anchors.leftMargin: 4 clip: true
anchors.rightMargin: 4 width: 320
text: "Title will go here" height: 36
heading: "h4"
}
}
Item { Label {
Layout.fillWidth: true anchors.top: parent.top
} anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 1
anchors.leftMargin: 4
anchors.rightMargin: 4
text: (Player.loading ? "Loading " : "Playing ") + (Player.currentIndex != null ? qsTr(Player.currentStream.name) : "")
heading: "h5"
}
TabBar { Label {
id: tabbar id: nowplaying_title
spacing: 10 anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 1
anchors.leftMargin: 4
anchors.rightMargin: 4
text: (Player.currentIndex != null ? qsTr(Player.currentStream.title) : "")
heading: "h3"
background: Item{} SequentialAnimation {
running: true
loops: Animation.Infinite
TabButton { NumberAnimation { target: nowplaying_title; property: "anchors.rightMargin"; from: 0; to: 320; duration: 5000 }
text: qsTr("Autoradio") NumberAnimation { target: nowplaying_title; property: "anchors.leftMargin"; from: 0; to: 320; duration: 5000 }
}
}
} }
TabButton {
text: qsTr("Live Mix") Item {
Layout.fillWidth: true
} }
TabButton {
text: qsTr("Deep Bass") TabBar {
} id: tabbar
} spacing: 10
Button {
text: "S" background: Item{}
onClicked: function() {
var component = Qt.createComponent("ViewSettings.qml") TabButton {
var window = component.createObject(root) text: qsTr("Autoradio")
window.show() }
TabButton {
text: qsTr("Live Mix")
}
TabButton {
text: qsTr("Deep Bass")
}
TabButton {
text: qsTr("Settings")
}
} }
// Button {
// text: "S"
// onClicked: function() {
// var component = Qt.createComponent("ViewSettings.qml")
// var window = component.createObject(root)
// window.show()
// }
// }
} }
} }
@@ -94,7 +110,7 @@ ApplicationWindow {
SwipeView { SwipeView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.margins: 10 Layout.margins: 20
interactive: false interactive: false
currentIndex: tabbar.currentIndex currentIndex: tabbar.currentIndex

View File

@@ -3,38 +3,39 @@ import QtMultimedia 6.8
pragma Singleton pragma Singleton
MediaPlayer { Item {
readonly property var streams: ([ readonly property string streamURLPrefix: "https://youradio.nonamesoft.xyz/youradio/api/"
readonly property string metadataURL: "https://youradio.nonamesoft.xyz/youradio/api/status-json.xsl"
readonly property var slugLookup: ({
"autoradio": 0,
"live": 1,
"bassboosted": 2
})
property var streams: ([
{ {
name: "Autoradio", name: "Autoradio",
streamURL: "https://youradio.nonamesoft.xyz/api/autoradio" slug: "autoradio",
title: "",
listeners: 0
}, },
{ {
name: "Live Mix", name: "Live Mix",
streamURL: "https://youradio.nonamesoft.xyz/api/live" slug: "live",
title: "",
listeners: 0
}, },
{ {
name: "Deep Bass", name: "Deep Bass",
streamURL: "https://youradio.nonamesoft.xyz/api/bassboosted" slug: "bassboosted",
title: "",
listeners: 0
} }
]) ])
property var failedConnAttempts: 0
id: player property alias playing: player.playing
source: ""
audioOutput: AudioOutput {
id: output
volume: 0.4
}
onErrorOccurred: function(error, errorString) {
const index = currentIndex
currentIndex = null
currentIndex = index;
}
property alias volume: output.volume property alias volume: output.volume
readonly property var loading: mediaStatus == Qt.LoadingMedia readonly property var loading: player.mediaStatus == Qt.LoadingMedia
property var currentIndex: null property var currentIndex: null
property var currentStream: null property var currentStream: null
@@ -49,7 +50,7 @@ MediaPlayer {
print("Starting playing stream no. " + index); print("Starting playing stream no. " + index);
currentIndex = index; currentIndex = index;
currentStream = streams[index]; currentStream = streams[index];
source = currentStream.streamURL; player.source = streamURLPrefix + currentStream.slug;
player.play(); player.play();
} }
@@ -60,7 +61,63 @@ MediaPlayer {
print("Stopping playback"); print("Stopping playback");
currentIndex = null; currentIndex = null;
currentStream = null; currentStream = null;
source = ""; player.source = "";
player.stop() player.stop()
} }
MediaPlayer {
id: player
source: ""
audioOutput: AudioOutput {
id: output
volume: 0.4
}
onErrorOccurred: function(error, errorString) {
const index = currentIndex
currentIndex = null
currentIndex = index;
}
}
Timer {
interval: 10000
repeat: true
running: true
triggeredOnStart: true
onTriggered: function() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
parent.failedConnAttempts = 0;
// try {
const object = JSON.parse(xhr.responseText.toString()).icestats;
object.source.forEach(station => {
const index = parent.slugLookup[station.server_name];
if (index == null) {
console.warn("Unknown slug encountered in metadata: " + station.server_name);
return
}
parent.streams[index].title = station.title;
parent.streams[index].listeners = station.listeners;
if (index == parent.currentIndex) {
parent.currentStream.title = station.title;
parent.currentStream.listeners = station.listeners;
}
});
// } catch {
// console.error("Failed deserializing metadata response");
// }
}
}
xhr.open("GET", parent.metadataURL);
xhr.timeout = 10000;
xhr.ontimeout = function() {
console.log("Metadata request timed out after 10 seconds");
parent.failedConnAttempts++;
}
xhr.send();
}
}
} }

View File

@@ -23,22 +23,22 @@ Item {
primaryAlt: "#0056b3", primaryAlt: "#0056b3",
secondary: "#009eff", secondary: "#009eff",
secondaryAlt: "#0076b3", secondaryAlt: "#0076b3",
surface1: "#323232", surface1: "#373737",
surface0: "#282828", surface0: "#2a2a2a",
background: "#1f1f1f" background: "#1f1f1f"
}) })
} }
readonly property string fontFamily: "Arial" readonly property string fontFamily: "Arial"
readonly property var fontSize: ({ readonly property var fontSize: ({
h1: 32, h1: 26,
h2: 24, h2: 24,
h3: 18, h3: 18,
h4: 16, h4: 16,
h5: 13, h5: 12,
h6: 10, // h6: 10,
p: 14, p: 12,
base: 14, base: 12,
button: 12 button: 12
}) })

View File

@@ -20,14 +20,14 @@ ColumnLayout {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Title: " text: "Title: " + (index != null ? Player.streams[index].title : "")
heading: "h3" heading: "h3"
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Listeners: " text: "Listeners: " + (index != null ? Player.streams[index].listeners : 0)
heading: "h3" heading: "h3"
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
@@ -62,7 +62,7 @@ ColumnLayout {
Layout.leftMargin: 5 Layout.leftMargin: 5
from: 0.1 from: 0.1
to: 1.1 to: 1.1
stepSize: 0.1 stepSize: 0.05
value: Player.volume + 0.1 value: Player.volume + 0.1
onMoved: Player.volume = value - 0.1 onMoved: Player.volume = value - 0.1
} }