mirror of
https://github.com/spalencsar/bearwave.git
synced 2026-07-06 14:24:14 +02:00
Replace the modal About dialog with an embedded About page and introduce a three-pane desktop layout: persistent sidebar navigation, flat station list, right-side details panel, and compact player bar. Load the GPLv3 license text from C++ and expose it to QML as context data. Normalize i18n source strings to English, complete German and Russian translations (133 strings each), and centralize page navigation helpers in Main.qml. Simplify compact HeaderNavigation and extend .gitignore for local build artifacts.
191 lines
6.5 KiB
QML
191 lines
6.5 KiB
QML
// 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
|
|
|
|
import theme 1.0
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
required property var app
|
|
|
|
implicitHeight: 76
|
|
radius: 0
|
|
color: BearTheme.panel
|
|
border.color: "transparent"
|
|
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
height: 1
|
|
color: BearTheme.cardBorder
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 12
|
|
anchors.rightMargin: 12
|
|
anchors.topMargin: 9
|
|
anchors.bottomMargin: 9
|
|
spacing: 12
|
|
|
|
Rectangle {
|
|
Layout.preferredWidth: 56
|
|
Layout.preferredHeight: 56
|
|
radius: 6
|
|
color: "#34353b"
|
|
clip: true
|
|
border.color: "transparent"
|
|
|
|
Image {
|
|
id: coverImage
|
|
anchors.fill: parent
|
|
source: {
|
|
if (app.backend && app.backend.player && app.backend.player.currentCoverArtUrl
|
|
&& app.backend.player.currentCoverArtUrl !== "") {
|
|
return app.backend.player.currentCoverArtUrl
|
|
}
|
|
if (app.backend && app.backend.currentStation && app.backend.currentStation.favicon
|
|
&& app.backend.currentStation.favicon.startsWith("https://")) {
|
|
return app.backend.currentStation.favicon
|
|
}
|
|
return "qrc:/assets/app/bearwave.png"
|
|
}
|
|
fillMode: (app.backend && app.backend.player && app.backend.player.currentCoverArtUrl
|
|
&& app.backend.player.currentCoverArtUrl !== "")
|
|
? Image.PreserveAspectCrop : Image.PreserveAspectFit
|
|
smooth: true
|
|
asynchronous: true
|
|
anchors.margins: {
|
|
if (app.backend && app.backend.player && app.backend.player.currentCoverArtUrl
|
|
&& app.backend.player.currentCoverArtUrl !== "") {
|
|
return 0
|
|
}
|
|
if (app.backend && app.backend.currentStation && app.backend.currentStation.favicon
|
|
&& app.backend.currentStation.favicon.startsWith("https://")) {
|
|
return 8
|
|
}
|
|
return 10
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
spacing: 3
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: app.backend && app.backend.player
|
|
? (app.backend.player.currentStationName || qsTr("No station selected"))
|
|
: qsTr("No station selected")
|
|
color: BearTheme.textMain
|
|
font.pixelSize: 14
|
|
font.bold: true
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: app.backend && app.backend.player && app.backend.player.currentNowPlaying.length > 0
|
|
? (qsTr("Now playing: ") + app.backend.player.currentNowPlaying)
|
|
: qsTr("Live radio")
|
|
color: BearTheme.textMuted
|
|
font.pixelSize: 12
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.alignment: Qt.AlignVCenter
|
|
spacing: 8
|
|
|
|
Button {
|
|
text: "⏮"
|
|
Layout.preferredWidth: 42
|
|
Layout.preferredHeight: 30
|
|
enabled: app.backend ? app.backend.hasPreviousStation() : false
|
|
onClicked: {
|
|
if (app.backend) {
|
|
app.backend.playPreviousStation()
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: app.backend && app.backend.player && app.backend.player.playing ? "⏸" : "▶"
|
|
Layout.preferredWidth: 42
|
|
Layout.preferredHeight: 30
|
|
onClicked: {
|
|
if (app.backend && app.backend.player) {
|
|
app.backend.player.togglePlayPause()
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: "⏹"
|
|
Layout.preferredWidth: 42
|
|
Layout.preferredHeight: 30
|
|
onClicked: {
|
|
if (app.backend && app.backend.player) {
|
|
app.backend.player.stop()
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: "⏭"
|
|
Layout.preferredWidth: 42
|
|
Layout.preferredHeight: 30
|
|
enabled: app.backend ? app.backend.hasNextStation() : false
|
|
onClicked: {
|
|
if (app.backend) {
|
|
app.backend.playNextStation()
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: muteButton
|
|
text: (app.backend && app.backend.player && app.backend.player.volume > 0) ? "🔊" : "🔇"
|
|
Layout.preferredWidth: 36
|
|
Layout.preferredHeight: 30
|
|
property real lastVolume: 0.5
|
|
|
|
ToolTip.visible: hovered
|
|
ToolTip.text: (app.backend && app.backend.player && app.backend.player.volume > 0)
|
|
? qsTr("Mute") : qsTr("Unmute")
|
|
|
|
onClicked: {
|
|
if (app.backend && app.backend.player) {
|
|
if (app.backend.player.volume > 0) {
|
|
lastVolume = app.backend.player.volume
|
|
app.backend.player.setVolume(0)
|
|
} else {
|
|
app.backend.player.setVolume(lastVolume > 0 ? lastVolume : 0.5)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Slider {
|
|
Layout.preferredWidth: app.width < 1180 ? 115 : 160
|
|
from: 0
|
|
to: 1
|
|
value: app.backend && app.backend.player ? app.backend.player.volume : 0.5
|
|
onMoved: {
|
|
if (app.backend && app.backend.player) {
|
|
app.backend.player.setVolume(value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|