// The countdown ring, drawn with Canvas. // // A hero number inside a progress arc: the number is what you read, the arc is // the glance. The arc colour is the only thing that says focus vs break. import QtQuick import QtQuick.Controls.Material Item { id: dial property real progress: 0 // 0..1 elapsed property string clockText: "00:00" property string label: "" property string sublabel: "" property color accent: "#2a78d6" property bool paused: false implicitWidth: 260 implicitHeight: 260 onProgressChanged: canvas.requestPaint() onAccentChanged: canvas.requestPaint() onPausedChanged: canvas.requestPaint() Canvas { id: canvas anchors.fill: parent antialiasing: true onPaint: { var ctx = getContext("2d") ctx.reset() var centre = Math.min(width, height) / 2 var stroke = Math.max(10, centre * 0.11) var radius = centre - stroke ctx.lineCap = "round" ctx.lineWidth = stroke ctx.beginPath() ctx.strokeStyle = Qt.rgba(0.5, 0.5, 0.5, 0.18) ctx.arc(centre, centre, radius, 0, Math.PI * 2) ctx.stroke() var remaining = 1 - Math.max(0, Math.min(1, dial.progress)) if (remaining > 0) { ctx.beginPath() ctx.globalAlpha = dial.paused ? 0.45 : 1 ctx.strokeStyle = dial.accent ctx.arc(centre, centre, radius, -Math.PI / 2, -Math.PI / 2 + remaining * Math.PI * 2) ctx.stroke() } } } Column { anchors.centerIn: parent spacing: 4 width: parent.width * 0.72 Label { width: parent.width text: dial.label.toUpperCase() font.pixelSize: 11 font.letterSpacing: 1.5 opacity: 0.65 horizontalAlignment: Text.AlignHCenter } Label { width: parent.width text: dial.clockText font.pixelSize: Math.round(dial.width * 0.2) font.weight: Font.Light font.family: "Roboto Mono, monospace" opacity: dial.paused ? 0.6 : 1 horizontalAlignment: Text.AlignHCenter } Label { width: parent.width text: dial.sublabel visible: dial.sublabel !== "" font.pixelSize: 13 opacity: 0.75 elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter } } }