diff --git a/src/qml.qrc b/src/qml.qrc
index 822f7c5..39c8ee5 100644
--- a/src/qml.qrc
+++ b/src/qml.qrc
@@ -15,6 +15,8 @@
qml/components/AddStationDialog.qml
qml/components/EditStationDialog.qml
qml/components/LoadingOverlay.qml
+ qml/components/ToastPopup.qml
+ qml/components/StationListPanel.qml
qml/utils/FlagUtils.js
diff --git a/src/qml/Main.qml b/src/qml/Main.qml
index 750906c..a592ed5 100644
--- a/src/qml/Main.qml
+++ b/src/qml/Main.qml
@@ -31,10 +31,10 @@ ApplicationWindow {
property string selectedWorldType: ""
property string countrySearchText: ""
property alias searchField: searchToolbar.searchField
+ property alias stationList: stationPanel.stationList
function toast(message) {
- toastLabel.text = message
- toastPopup.open()
+ toastPopup.show(message)
}
function resetSearchFilter() {
@@ -192,27 +192,11 @@ ApplicationWindow {
app: root
}
- ScrollView {
- id: stationScrollView
+ StationListPanel {
+ id: stationPanel
Layout.fillWidth: true
Layout.fillHeight: true
- visible: !(currentPage === "world" && selectedWorldCategory === "")
- clip: true
- ScrollBar.vertical.policy: ScrollBar.AlwaysOn
-
- ListView {
- id: stationList
- width: stationScrollView.availableWidth
- spacing: 8
- model: activeModel()
- visible: count > 0
-
- delegate: StationCard {
- app: root
- compactMode: root.compactMode
- listWidth: stationScrollView.availableWidth
- }
- }
+ app: root
}
WorldCategories {
@@ -223,23 +207,6 @@ ApplicationWindow {
compactMode: root.compactMode
}
}
-
- Column {
- anchors.centerIn: parent
- spacing: 8
- visible: stationList.count === 0 && !(currentPage === "world" && selectedWorldCategory === "")
-
- Label {
- text: currentPage === "history" ? qsTr("No playback history") : qsTr("No stations loaded yet")
- color: BearTheme.textMain
- font.bold: true
- }
-
- Label {
- text: currentPage === "history" ? qsTr("Play some stations to build history") : qsTr("Load DE/NL stations or use search")
- color: BearTheme.textMuted
- }
- }
}
PlayerBar {
@@ -275,30 +242,9 @@ ApplicationWindow {
compactMode: root.compactMode
}
- Popup {
+ ToastPopup {
id: toastPopup
- x: (root.width - width) / 2
- y: root.height - height - 20
- padding: 10
- closePolicy: Popup.NoAutoClose
- background: Rectangle {
- radius: 10
- color: "#24364e"
- border.color: BearTheme.accent
- }
-
- contentItem: Label {
- id: toastLabel
- color: BearTheme.textMain
- font.pixelSize: 12
- }
-
- Timer {
- interval: 1400
- running: toastPopup.visible
- repeat: false
- onTriggered: toastPopup.close()
- }
+ window: root
}
Timer {
diff --git a/src/qml/components/StationListPanel.qml b/src/qml/components/StationListPanel.qml
new file mode 100644
index 0000000..5ae17d1
--- /dev/null
+++ b/src/qml/components/StationListPanel.qml
@@ -0,0 +1,59 @@
+// Copyright (c) 2026 Sebastian Palencsar
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+import theme 1.0
+
+Item {
+ id: root
+
+ required property var app
+
+ property alias stationList: stationList
+
+ readonly property bool showEmptyState: stationList.count === 0
+ && !(app.currentPage === "world" && app.selectedWorldCategory === "")
+
+ ScrollView {
+ id: stationScrollView
+ anchors.fill: parent
+ visible: !(app.currentPage === "world" && app.selectedWorldCategory === "")
+ clip: true
+ ScrollBar.vertical.policy: ScrollBar.AlwaysOn
+
+ ListView {
+ id: stationList
+ width: stationScrollView.availableWidth
+ spacing: 8
+ model: app.activeModel()
+ visible: count > 0
+
+ delegate: StationCard {
+ app: root.app
+ compactMode: root.app.compactMode
+ listWidth: stationScrollView.availableWidth
+ }
+ }
+ }
+
+ Column {
+ anchors.centerIn: parent
+ spacing: 8
+ visible: root.showEmptyState
+
+ Label {
+ text: app.currentPage === "history" ? qsTr("No playback history") : qsTr("No stations loaded yet")
+ color: BearTheme.textMain
+ font.bold: true
+ }
+
+ Label {
+ text: app.currentPage === "history"
+ ? qsTr("Play some stations to build history")
+ : qsTr("Load DE/NL stations or use search")
+ color: BearTheme.textMuted
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/qml/components/ToastPopup.qml b/src/qml/components/ToastPopup.qml
new file mode 100644
index 0000000..26653b9
--- /dev/null
+++ b/src/qml/components/ToastPopup.qml
@@ -0,0 +1,42 @@
+// Copyright (c) 2026 Sebastian Palencsar
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+import theme 1.0
+
+Popup {
+ id: root
+
+ required property var window
+
+ padding: 10
+ closePolicy: Popup.NoAutoClose
+ x: (window.width - width) / 2
+ y: window.height - height - 20
+
+ function show(message) {
+ toastLabel.text = message
+ open()
+ }
+
+ background: Rectangle {
+ radius: 10
+ color: "#24364e"
+ border.color: BearTheme.accent
+ }
+
+ contentItem: Label {
+ id: toastLabel
+ color: BearTheme.textMain
+ font.pixelSize: 12
+ }
+
+ Timer {
+ interval: 1400
+ running: root.visible
+ repeat: false
+ onTriggered: root.close()
+ }
+}
\ No newline at end of file
diff --git a/src/qml/components/qmldir b/src/qml/components/qmldir
index 0c07e64..70e0b82 100644
--- a/src/qml/components/qmldir
+++ b/src/qml/components/qmldir
@@ -8,4 +8,6 @@ PlayerBar 1.0 PlayerBar.qml
AboutDialog 1.0 AboutDialog.qml
AddStationDialog 1.0 AddStationDialog.qml
EditStationDialog 1.0 EditStationDialog.qml
-LoadingOverlay 1.0 LoadingOverlay.qml
\ No newline at end of file
+LoadingOverlay 1.0 LoadingOverlay.qml
+ToastPopup 1.0 ToastPopup.qml
+StationListPanel 1.0 StationListPanel.qml
\ No newline at end of file