diff --git a/src/qml.qrc b/src/qml.qrc
index bdcaac2..822f7c5 100644
--- a/src/qml.qrc
+++ b/src/qml.qrc
@@ -12,6 +12,9 @@
qml/components/WorldCategories.qml
qml/components/PlayerBar.qml
qml/components/AboutDialog.qml
+ qml/components/AddStationDialog.qml
+ qml/components/EditStationDialog.qml
+ qml/components/LoadingOverlay.qml
qml/utils/FlagUtils.js
diff --git a/src/qml/Main.qml b/src/qml/Main.qml
index 0ccddbf..750906c 100644
--- a/src/qml/Main.qml
+++ b/src/qml/Main.qml
@@ -248,38 +248,8 @@ ApplicationWindow {
}
}
- Rectangle {
- visible: backend && backend.loading
- anchors.fill: parent
- color: "#7f0b121a"
- z: 20
-
- Rectangle {
- anchors.centerIn: parent
- width: 210
- height: 110
- radius: 12
- color: BearTheme.panel
- border.color: BearTheme.cardBorder
-
- Column {
- anchors.centerIn: parent
- spacing: 10
-
- BusyIndicator {
- running: true
- width: 36
- height: 36
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- Label {
- text: qsTr("Loading stations...")
- color: BearTheme.textMain
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
+ LoadingOverlay {
+ app: root
}
Component.onCompleted: {
@@ -288,75 +258,16 @@ ApplicationWindow {
}
}
- Dialog {
+ AddStationDialog {
id: addDialog
- title: qsTr("Add station manually")
- modal: true
- anchors.centerIn: parent
- width: compactMode ? 320 : 420
- standardButtons: Dialog.Ok | Dialog.Cancel
-
- contentItem: ColumnLayout {
- spacing: 8
- TextField { id: manualName; Layout.fillWidth: true; placeholderText: qsTr("Name") }
- TextField { id: manualUrl; Layout.fillWidth: true; placeholderText: qsTr("Stream URL (http/https)") }
- TextField { id: manualCountry; Layout.fillWidth: true; placeholderText: qsTr("Country (optional)") }
- }
-
- onAccepted: {
- if (backend) {
- backend.addManualStation(manualName.text, manualUrl.text, manualCountry.text)
- toast(qsTr("Station added"))
- }
- manualName.text = ""
- manualUrl.text = ""
- manualCountry.text = ""
- }
+ app: root
+ compactMode: root.compactMode
}
- Dialog {
+ EditStationDialog {
id: editDialog
- title: qsTr("Edit station")
- modal: true
- anchors.centerIn: parent
- width: compactMode ? 320 : 420
- standardButtons: Dialog.Ok | Dialog.Cancel
-
- property var stationObject: null
-
- contentItem: ColumnLayout {
- spacing: 8
- TextField { id: editName; Layout.fillWidth: true; placeholderText: qsTr("Name") }
- TextField { id: editUrl; Layout.fillWidth: true; placeholderText: qsTr("Stream URL (http/https)") }
- TextField { id: editCountry; Layout.fillWidth: true; placeholderText: qsTr("Country (optional)") }
- }
-
- function setupAndOpen() {
- if (stationObject) {
- editName.text = stationObject.name || ""
- editUrl.text = stationObject.url || ""
- editCountry.text = (stationObject.country === qsTr("Manual") ? "" : (stationObject.country || ""))
- open()
- }
- }
-
- onAccepted: {
- if (backend && stationObject) {
- backend.editManualStation(stationObject, editName.text, editUrl.text, editCountry.text)
- toast(qsTr("Station updated"))
- }
- stationObject = null
- editName.text = ""
- editUrl.text = ""
- editCountry.text = ""
- }
-
- onRejected: {
- stationObject = null
- editName.text = ""
- editUrl.text = ""
- editCountry.text = ""
- }
+ app: root
+ compactMode: root.compactMode
}
AboutDialog {
diff --git a/src/qml/components/AddStationDialog.qml b/src/qml/components/AddStationDialog.qml
new file mode 100644
index 0000000..c639cbc
--- /dev/null
+++ b/src/qml/components/AddStationDialog.qml
@@ -0,0 +1,36 @@
+// Copyright (c) 2026 Sebastian Palencsar
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Dialog {
+ id: root
+
+ required property var app
+ required property bool compactMode
+
+ title: qsTr("Add station manually")
+ modal: true
+ anchors.centerIn: parent
+ width: compactMode ? 320 : 420
+ standardButtons: Dialog.Ok | Dialog.Cancel
+
+ contentItem: ColumnLayout {
+ spacing: 8
+ TextField { id: manualName; Layout.fillWidth: true; placeholderText: qsTr("Name") }
+ TextField { id: manualUrl; Layout.fillWidth: true; placeholderText: qsTr("Stream URL (http/https)") }
+ TextField { id: manualCountry; Layout.fillWidth: true; placeholderText: qsTr("Country (optional)") }
+ }
+
+ onAccepted: {
+ if (app.backend) {
+ app.backend.addManualStation(manualName.text, manualUrl.text, manualCountry.text)
+ app.toast(qsTr("Station added"))
+ }
+ manualName.text = ""
+ manualUrl.text = ""
+ manualCountry.text = ""
+ }
+}
\ No newline at end of file
diff --git a/src/qml/components/EditStationDialog.qml b/src/qml/components/EditStationDialog.qml
new file mode 100644
index 0000000..6b4e704
--- /dev/null
+++ b/src/qml/components/EditStationDialog.qml
@@ -0,0 +1,54 @@
+// Copyright (c) 2026 Sebastian Palencsar
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Dialog {
+ id: root
+
+ required property var app
+ required property bool compactMode
+
+ property var stationObject: null
+
+ title: qsTr("Edit station")
+ modal: true
+ anchors.centerIn: parent
+ width: compactMode ? 320 : 420
+ standardButtons: Dialog.Ok | Dialog.Cancel
+
+ contentItem: ColumnLayout {
+ spacing: 8
+ TextField { id: editName; Layout.fillWidth: true; placeholderText: qsTr("Name") }
+ TextField { id: editUrl; Layout.fillWidth: true; placeholderText: qsTr("Stream URL (http/https)") }
+ TextField { id: editCountry; Layout.fillWidth: true; placeholderText: qsTr("Country (optional)") }
+ }
+
+ function setupAndOpen() {
+ if (stationObject) {
+ editName.text = stationObject.name || ""
+ editUrl.text = stationObject.url || ""
+ editCountry.text = (stationObject.country === qsTr("Manual") ? "" : (stationObject.country || ""))
+ open()
+ }
+ }
+
+ function clearFields() {
+ stationObject = null
+ editName.text = ""
+ editUrl.text = ""
+ editCountry.text = ""
+ }
+
+ onAccepted: {
+ if (app.backend && stationObject) {
+ app.backend.editManualStation(stationObject, editName.text, editUrl.text, editCountry.text)
+ app.toast(qsTr("Station updated"))
+ }
+ clearFields()
+ }
+
+ onRejected: clearFields()
+}
\ No newline at end of file
diff --git a/src/qml/components/LoadingOverlay.qml b/src/qml/components/LoadingOverlay.qml
new file mode 100644
index 0000000..2201cee
--- /dev/null
+++ b/src/qml/components/LoadingOverlay.qml
@@ -0,0 +1,45 @@
+// 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
+
+Rectangle {
+ id: root
+
+ required property var app
+
+ visible: app.backend && app.backend.loading
+ anchors.fill: parent
+ color: "#7f0b121a"
+ z: 20
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 210
+ height: 110
+ radius: 12
+ color: BearTheme.panel
+ border.color: BearTheme.cardBorder
+
+ Column {
+ anchors.centerIn: parent
+ spacing: 10
+
+ BusyIndicator {
+ running: true
+ width: 36
+ height: 36
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Label {
+ text: qsTr("Loading stations...")
+ color: BearTheme.textMain
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/qml/components/qmldir b/src/qml/components/qmldir
index 0cee098..0c07e64 100644
--- a/src/qml/components/qmldir
+++ b/src/qml/components/qmldir
@@ -5,4 +5,7 @@ StationCard 1.0 StationCard.qml
WorldCategoryHeader 1.0 WorldCategoryHeader.qml
WorldCategories 1.0 WorldCategories.qml
PlayerBar 1.0 PlayerBar.qml
-AboutDialog 1.0 AboutDialog.qml
\ No newline at end of file
+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