diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index 82fe9df0..347ec589 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -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