mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-06-01 18:15:41 +00:00
feat: Add circular progress bar to MediaMini widget
This commit is contained in:
@@ -321,14 +321,78 @@ Item {
|
||||
Layout.preferredWidth: Math.round(21 * scaling)
|
||||
Layout.preferredHeight: Math.round(21 * scaling)
|
||||
|
||||
// Background for progress circle
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: Color.transparent
|
||||
}
|
||||
|
||||
// Progress circle
|
||||
Canvas {
|
||||
id: progressCanvas
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0 // Align exactly with parent to avoid clipping
|
||||
z: 0 // Behind the album art
|
||||
|
||||
// Calculate progress ratio: 0 to 1
|
||||
property real progressRatio: {
|
||||
if (!MediaService.currentPlayer || MediaService.trackLength <= 0)
|
||||
return 0;
|
||||
const r = MediaService.currentPosition / MediaService.trackLength;
|
||||
if (isNaN(r) || !isFinite(r))
|
||||
return 0;
|
||||
return Math.max(0, Math.min(1, r));
|
||||
}
|
||||
|
||||
onProgressRatioChanged: requestPaint()
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
var centerX = width / 2;
|
||||
var centerY = height / 2;
|
||||
var radius = Math.min(width, height) / 2 - 3; // Larger radius to create visible ring
|
||||
|
||||
ctx.reset();
|
||||
|
||||
// Background circle (full track, not played yet)
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
|
||||
ctx.lineWidth = 3; // Thicker line for better visibility
|
||||
ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.4); // More opaque for better visibility
|
||||
ctx.stroke();
|
||||
|
||||
// Progress arc (played portion)
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progressRatio * 2 * Math.PI);
|
||||
ctx.lineWidth = 3; // Thicker line for better visibility
|
||||
ctx.strokeStyle = Color.mPrimary; // Use primary color for progress
|
||||
ctx.lineCap = "round";
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection to update progress when media position changes
|
||||
Connections {
|
||||
target: MediaService
|
||||
function onCurrentPositionChanged() {
|
||||
progressCanvas.requestPaint();
|
||||
}
|
||||
function onTrackLengthChanged() {
|
||||
progressCanvas.requestPaint();
|
||||
}
|
||||
}
|
||||
|
||||
NImageCircled {
|
||||
id: trackArt
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4 // Make album art slightly smaller to reveal progress ring underneath
|
||||
imagePath: MediaService.trackArtUrl
|
||||
fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play"
|
||||
fallbackIconSize: 10
|
||||
borderWidth: 0
|
||||
border.color: Color.transparent
|
||||
z: 1 // In front of the progress circle
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -484,6 +548,52 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Progress circle for vertical layout - follows background radius
|
||||
Canvas {
|
||||
id: progressCanvasVertical
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0 // Align with parent container (mainContainer which matches mediaMini)
|
||||
visible: isVerticalBar
|
||||
z: 0 // Behind other content
|
||||
|
||||
// Calculate progress ratio: 0 to 1
|
||||
property real progressRatio: {
|
||||
if (!MediaService.currentPlayer || MediaService.trackLength <= 0)
|
||||
return 0;
|
||||
const r = MediaService.currentPosition / MediaService.trackLength;
|
||||
if (isNaN(r) || !isFinite(r))
|
||||
return 0;
|
||||
return Math.max(0, Math.min(1, r));
|
||||
}
|
||||
|
||||
onProgressRatioChanged: requestPaint()
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
var centerX = width / 2;
|
||||
var centerY = height / 2;
|
||||
// Align with mediaMini radius which is circular in vertical mode
|
||||
var radius = Math.min(width, height) / 2 - 4; // Position ring near the outer edge of background
|
||||
|
||||
ctx.reset();
|
||||
|
||||
// Background circle (full track, not played yet)
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
|
||||
ctx.lineWidth = 3; // Thicker line for better visibility in vertical layout
|
||||
ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.4); // More opaque for better visibility
|
||||
ctx.stroke();
|
||||
|
||||
// Progress arc (played portion)
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progressRatio * 2 * Math.PI);
|
||||
ctx.lineWidth = 3; // Thicker line for better visibility in vertical layout
|
||||
ctx.strokeStyle = Color.mPrimary; // Use primary color for progress
|
||||
ctx.lineCap = "round";
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical layout for left/right bars - icon only
|
||||
Item {
|
||||
id: verticalLayout
|
||||
@@ -507,10 +617,22 @@ Item {
|
||||
pointSize: Style.fontSizeL * scaling
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
z: 1 // In front of the progress circle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connection to update vertical progress when media position changes
|
||||
Connections {
|
||||
target: MediaService
|
||||
function onCurrentPositionChanged() {
|
||||
progressCanvasVertical.requestPaint();
|
||||
}
|
||||
function onTrackLengthChanged() {
|
||||
progressCanvasVertical.requestPaint();
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse area for hover detection
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
Reference in New Issue
Block a user