Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 161 additions & 42 deletions BarWidget.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ BarWidget {
readonly property bool playing: waveformService ? waveformService.playing : false
readonly property bool showControls: setting("showControls", true) === true
readonly property bool showTitle: setting("showTitle", true) === true
readonly property bool showArtist: String(setting("showArtist", false)).toLowerCase() === "true"
readonly property bool showFullTitle: String(setting("showFullTitle", false)).toLowerCase() === "true"
readonly property bool groupControls: String(setting("groupControls", false)).toLowerCase() === "true"
readonly property bool showCover: String(setting("showCover", false)).toLowerCase() === "true"
readonly property bool hideWhenPaused: setting("hideWhenPaused", false) === true
readonly property real waveformWidth: Math.min(240,
Math.max(40, Number(setting("waveformWidth", 72)) || 72))
readonly property string artUrl: waveformService ? waveformService.trackArtUrl : ""
readonly property real maxTitleWidth: Math.min(320,
Math.max(60, Number(setting("maxTitleWidth", 150)) || 150))

Expand Down Expand Up @@ -75,24 +80,41 @@ BarWidget {
anchors.centerIn: parent
spacing: Style.space(3)

Button {
visible: root.showControls
enabled: root.actionEnabled("previous")
opacity: enabled ? 1 : 0.35
iconText: "󰒮"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
tooltipText: "Previous"
onClicked: if (root.waveformService) root.waveformService.runAction("previous")
}
Item {
id: prevLeft
visible: root.showControls && !root.groupControls
implicitWidth: prevLeftBtn.implicitWidth
implicitHeight: prevLeftBtn.implicitHeight
readonly property bool tooltipHovered: prevLeftHover.containsMouse

Button {
id: prevLeftBtn
anchors.fill: parent
enabled: root.actionEnabled("previous")
opacity: enabled ? 1 : 0.35
iconText: "󰒮"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
onClicked: if (root.waveformService) root.waveformService.runAction("previous")
}

MouseArea {
id: prevLeftHover
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered: if (root.bar) root.bar.showTooltip(prevLeft, "Previous")
onExited: if (root.bar) root.bar.hideTooltip(prevLeft)
}
}
Item {
id: mediaButton
implicitWidth: mediaRow.implicitWidth
implicitHeight: Math.max(Style.space(24), mediaRow.implicitHeight)
readonly property bool tooltipHovered: mediaHover.containsMouse

Row {
id: mediaRow
Expand All @@ -110,9 +132,26 @@ BarWidget {
anchors.verticalCenter: parent.verticalCenter
}

Item {
visible: root.showCover && root.artUrl !== "" && !root.vertical
width: Style.space(18)
height: Style.space(18)
clip: true
anchors.verticalCenter: parent.verticalCenter

Image {
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
asynchronous: true
source: root.artUrl
}
}

Item {
visible: root.showTitle && !root.vertical
width: visible ? Math.min(root.maxTitleWidth, titleText.implicitWidth) : 0
width: visible ? (root.showFullTitle
? titleText.implicitWidth
: Math.min(root.maxTitleWidth, titleText.implicitWidth)) : 0
height: titleText.implicitHeight
clip: true
anchors.verticalCenter: parent.verticalCenter
Expand All @@ -121,16 +160,24 @@ BarWidget {
id: titleText
width: parent.width
height: implicitHeight
text: root.waveformService ? root.waveformService.title : ""
text: {
if (!root.waveformService) return ""
var title = root.waveformService.title || ""
if (root.showArtist && root.waveformService.artist) {
return title + " \u2014 " + root.waveformService.artist
}
return title
}
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
fontPixelSize: Style.font.bodySmall
active: !root.opened
active: !root.opened && !root.showFullTitle
}
}
}

MouseArea {
id: mediaHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
Expand All @@ -141,39 +188,111 @@ BarWidget {
root.waveformService.runAction(wheel.angleDelta.y > 0 ? "previous" : "next")
}
onEntered: if (root.bar && root.waveformService)
root.bar.showTooltip(root, root.waveformService.title
root.bar.showTooltip(mediaButton, root.waveformService.title
+ (root.waveformService.artist ? " — " + root.waveformService.artist : ""))
onExited: if (root.bar) root.bar.hideTooltip(root)
onExited: if (root.bar) root.bar.hideTooltip(mediaButton)
}
}

Button {
Row {
id: controlsGroup
visible: root.showControls
enabled: root.actionEnabled("playPause")
opacity: enabled ? 1 : 0.35
iconText: root.playing ? "󰏤" : "󰐊"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(4)
verticalPadding: Style.space(2)
tooltipText: root.playing ? "Pause" : "Play"
onClicked: if (root.waveformService) root.waveformService.runAction("playPause")
}
spacing: Style.space(3)

Button {
visible: root.showControls
enabled: root.actionEnabled("next")
opacity: enabled ? 1 : 0.35
iconText: "󰒭"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
tooltipText: "Next"
onClicked: if (root.waveformService) root.waveformService.runAction("next")
Item {
id: prevButton
visible: root.groupControls
implicitWidth: prevBtn.implicitWidth
implicitHeight: prevBtn.implicitHeight
readonly property bool tooltipHovered: prevHover.containsMouse

Button {
id: prevBtn
anchors.fill: parent
enabled: root.actionEnabled("previous")
opacity: enabled ? 1 : 0.35
iconText: "󰒮"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
onClicked: if (root.waveformService) root.waveformService.runAction("previous")
}

MouseArea {
id: prevHover
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered: if (root.bar) root.bar.showTooltip(prevButton, "Previous")
onExited: if (root.bar) root.bar.hideTooltip(prevButton)
}
}

Item {
id: playButton
visible: true
implicitWidth: playBtn.implicitWidth
implicitHeight: playBtn.implicitHeight
readonly property bool tooltipHovered: playHover.containsMouse

Button {
id: playBtn
anchors.fill: parent
enabled: root.actionEnabled("playPause")
opacity: enabled ? 1 : 0.35
iconText: root.playing ? "󰏤" : "󰐊"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
onClicked: if (root.waveformService) root.waveformService.runAction("playPause")
}

MouseArea {
id: playHover
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered: if (root.bar) root.bar.showTooltip(playButton, root.playing ? "Pause" : "Play")
onExited: if (root.bar) root.bar.hideTooltip(playButton)
}
}

Item {
id: nextButton
visible: true
implicitWidth: nextBtn.implicitWidth
implicitHeight: nextBtn.implicitHeight
readonly property bool tooltipHovered: nextHover.containsMouse

Button {
id: nextBtn
anchors.fill: parent
enabled: root.actionEnabled("next")
opacity: enabled ? 1 : 0.35
iconText: "󰒭"
foreground: root.bar ? root.bar.barForeground : Color.foreground
fontFamily: root.bar ? root.bar.fontFamily : Style.font.family
iconSize: Style.font.body
horizontalPadding: Style.space(3)
verticalPadding: Style.space(2)
onClicked: if (root.waveformService) root.waveformService.runAction("next")
}

MouseArea {
id: nextHover
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered: if (root.bar) root.bar.showTooltip(nextButton, "Next")
onExited: if (root.bar) root.bar.hideTooltip(nextButton)
}
}
}

}

Column {
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## Unreleased

### Media and interface

- Added a `showArtist` setting to display the artist name after the track title
in the widget (matching the panel tooltip).
- Added a `showFullTitle` setting to show the whole track title without
truncating or horizontal scrolling.
- Added a `showCover` setting to show the album art thumbnail between the
waveform and the track title, and as the panel header art.
- Added a `groupControls` setting to keep the previous/play/pause/next buttons
grouped beside the waveform instead of splitting previous to the far side.
- Added an in-panel **Settings** section (behind a cog button) that toggles
title, artist, full-title, album-cover, controls, grouped-controls, and
hide-when-paused options.
- Used squared theming for the waveform bars and progress/volume controls via a
plugin-local `WavebarSlider`, keeping other Omarchy panels' sliders unchanged.
- Corrected panel tooltips to use the bar's native tooltip targets and made the
previous button tooltip switch targets when controls are grouped.

### Security

- Reintroduced opt-in album art with a hardened allowlist: only local `file://`
paths and trusted cover CDNs (Apple Music, Spotify, YouTube, Tidal/Deezer) are
ever loaded; all other MPRIS-provided URLs are rejected and treated as no
cover. The allowlist lives on the service so bar and panel share one check.

## 1.0.2 — 2026-09-02

### Security and lifecycle
Expand Down
Loading
Loading