diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-06-23 19:33:55 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-06-23 19:33:55 +1000 |
| commit | 92700bbd84511c0d2963d29c5346118322e67562 (patch) | |
| tree | a99f1eec415e32724ab7ac2f5357ffbf0a5467dd /modules/lock | |
| parent | drawers: give back focus when close (diff) | |
| download | caelestia-shell-92700bbd84511c0d2963d29c5346118322e67562.tar.gz caelestia-shell-92700bbd84511c0d2963d29c5346118322e67562.tar.bz2 caelestia-shell-92700bbd84511c0d2963d29c5346118322e67562.zip | |
lock: add media
Diffstat (limited to 'modules/lock')
| -rw-r--r-- | modules/lock/Backgrounds.qml | 66 | ||||
| -rw-r--r-- | modules/lock/Input.qml | 5 | ||||
| -rw-r--r-- | modules/lock/Lock.qml | 2 | ||||
| -rw-r--r-- | modules/lock/LockSurface.qml | 7 | ||||
| -rw-r--r-- | modules/lock/MediaPlaying.qml | 297 |
5 files changed, 376 insertions, 1 deletions
diff --git a/modules/lock/Backgrounds.qml b/modules/lock/Backgrounds.qml index 3bcedd6..d165ef3 100644 --- a/modules/lock/Backgrounds.qml +++ b/modules/lock/Backgrounds.qml @@ -15,6 +15,8 @@ Item { readonly property real inputTop: innerMask.anchors.margins + inputPath.height readonly property real weatherTop: innerMask.anchors.margins + weatherPath.height readonly property real weatherRight: innerMask.anchors.margins + weatherPath.width + readonly property real mediaBottom: innerMask.anchors.margins + mediaPath.height + readonly property real mediaRight: innerMask.anchors.margins + mediaPath.width anchors.fill: parent @@ -261,6 +263,70 @@ Item { } } } + + ShapePath { + id: mediaPath + + property int width: root.locked ? Config.lock.sizes.mediaWidth - Config.lock.sizes.border / 4 : 0 + property real height: root.locked ? Config.lock.sizes.mediaHeight : 0 + + readonly property real rounding: Appearance.rounding.large * 2 + readonly property real roundingX: width < rounding * 2 ? width / 2 : rounding + readonly property real roundingY: height < rounding * 2 ? height / 2 : rounding + + strokeWidth: -1 + fillColor: Config.border.colour + + startY: height + roundingY + + PathArc { + relativeX: mediaPath.roundingX + relativeY: -mediaPath.roundingY + radiusX: Math.min(mediaPath.rounding, mediaPath.width) + radiusY: Math.min(mediaPath.rounding, mediaPath.height) + } + PathLine { + relativeX: mediaPath.width - mediaPath.roundingX * 2 + relativeY: 0 + } + PathArc { + relativeX: mediaPath.roundingX + relativeY: -mediaPath.roundingY + radiusX: Math.min(mediaPath.rounding, mediaPath.width) + radiusY: Math.min(mediaPath.rounding, mediaPath.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(mediaPath.height - mediaPath.roundingY * 2) + } + PathArc { + relativeX: mediaPath.roundingX + relativeY: -mediaPath.roundingY + radiusX: Math.min(mediaPath.rounding, mediaPath.width) + radiusY: Math.min(mediaPath.rounding, mediaPath.height) + } + PathLine { + relativeX: -mediaPath.width - mediaPath.roundingX + relativeY: 0 + } + + Behavior on width { + Anim {} + } + + Behavior on height { + Anim {} + } + + Behavior on fillColor { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } } component Anim: NumberAnimation { diff --git a/modules/lock/Input.qml b/modules/lock/Input.qml index 922dce8..578ead0 100644 --- a/modules/lock/Input.qml +++ b/modules/lock/Input.qml @@ -79,6 +79,11 @@ ColumnLayout { radius: Appearance.rounding.small clip: true + onFocusChanged: { + if (!focus) + focus = true; + } + Keys.onPressed: event => { if (pam.active) return; diff --git a/modules/lock/Lock.qml b/modules/lock/Lock.qml index a5b6cfc..e0f41c3 100644 --- a/modules/lock/Lock.qml +++ b/modules/lock/Lock.qml @@ -34,7 +34,7 @@ Scope { CustomShortcut { name: "unlock" description: "Unlock the current session" - onPressed: lock.locked = false + onPressed: loader.item.locked = false } IpcHandler { diff --git a/modules/lock/LockSurface.qml b/modules/lock/LockSurface.qml index 4751c70..d99b3f3 100644 --- a/modules/lock/LockSurface.qml +++ b/modules/lock/LockSurface.qml @@ -99,6 +99,13 @@ WlSessionLockSurface { anchors.rightMargin: -backgrounds.weatherRight } + MediaPlaying { + anchors.bottom: parent.top + anchors.right: parent.left + anchors.bottomMargin: -backgrounds.mediaBottom + anchors.rightMargin: -backgrounds.mediaRight + } + component Anim: NumberAnimation { duration: Appearance.anim.durations.large easing.type: Easing.BezierSpline diff --git a/modules/lock/MediaPlaying.qml b/modules/lock/MediaPlaying.qml new file mode 100644 index 0000000..c297694 --- /dev/null +++ b/modules/lock/MediaPlaying.qml @@ -0,0 +1,297 @@ +import "root:/widgets" +import "root:/services" +import "root:/config" +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +RowLayout { + id: root + + spacing: Appearance.spacing.large * 2 + width: Config.lock.sizes.mediaWidth + + property real playerProgress: { + const active = Players.active; + return active?.length ? active.position / active.length : 0; + } + + Behavior on playerProgress { + NumberAnimation { + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + Timer { + running: Players.active?.isPlaying ?? false + interval: Config.dashboard.mediaUpdateInterval + triggeredOnStart: true + repeat: true + onTriggered: Players.active?.positionChanged() + } + + Item { + Layout.bottomMargin: Config.lock.sizes.border / 2 + + implicitWidth: Config.lock.sizes.mediaCoverSize + implicitHeight: Config.lock.sizes.mediaCoverSize + + ClippingWrapperRectangle { + anchors.fill: parent + + color: Colours.palette.m3surfaceContainerHigh + radius: Appearance.rounding.small + rotation: 9 + + Image { + anchors.fill: parent + + source: Players.active?.trackArtUrl ?? "" + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + } + + Behavior on color { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + Rectangle { + anchors.fill: parent + anchors.margins: -1 + border.width: Config.lock.sizes.mediaCoverBorder + border.color: Colours.palette.m3primary + color: "transparent" + radius: Appearance.rounding.small + rotation: 9 + + Behavior on border.color { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + StyledClippingRect { + anchors.fill: parent + + color: Colours.palette.m3surfaceContainerHigh + radius: Appearance.rounding.small + + border.width: Config.lock.sizes.mediaCoverBorder + border.color: Colours.palette.m3primary + + MaterialIcon { + anchors.centerIn: parent + + text: "art_track" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Config.lock.sizes.mediaCoverSize * 0.4 + } + + Image { + anchors.fill: parent + + source: Players.active?.trackArtUrl ?? "" + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + } + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + Layout.bottomMargin: Config.lock.sizes.border / 2 + Layout.rightMargin: Config.lock.sizes.border / 2 + Layout.fillWidth: true + + spacing: Appearance.spacing.small + + StyledText { + Layout.fillWidth: true + + animate: true + text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title") + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.large + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + + animate: true + text: (Players.active?.trackAlbum ?? qsTr("No media")) || qsTr("Unknown album") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.larger + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + + animate: true + text: (Players.active?.trackArtist ?? qsTr("No media")) || qsTr("Unknown artist") + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.larger + elide: Text.ElideRight + } + + RowLayout { + id: controls + + Layout.fillWidth: true + + spacing: Appearance.spacing.small + + Slider { + id: slider + + Layout.rightMargin: Appearance.spacing.small + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + value: root.playerProgress + onMoved: { + const active = Players.active; + if (active?.canSeek && active?.positionSupported) + active.position = value * active.length; + } + + background: Item { + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: slider.implicitHeight / 3 + anchors.bottomMargin: slider.implicitHeight / 3 + + implicitWidth: slider.handle.x - slider.implicitHeight / 6 + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + topRightRadius: slider.implicitHeight / 15 + bottomRightRadius: slider.implicitHeight / 15 + } + + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.topMargin: slider.implicitHeight / 3 + anchors.bottomMargin: slider.implicitHeight / 3 + + implicitWidth: parent.width - slider.handle.x - slider.handle.implicitWidth - slider.implicitHeight / 6 + + color: Colours.palette.m3surfaceContainer + radius: Appearance.rounding.full + topLeftRadius: slider.implicitHeight / 15 + bottomLeftRadius: slider.implicitHeight / 15 + } + } + + handle: StyledRect { + id: rect + + x: slider.visualPosition * slider.availableWidth + + implicitWidth: slider.implicitHeight / 4.5 + implicitHeight: slider.implicitHeight + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onPressed: event => event.accepted = false + } + } + } + + Control { + icon: "skip_previous" + canUse: Players.active?.canGoPrevious ?? false + + function onClicked(): void { + Players.active?.previous(); + } + } + + Control { + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + canUse: Players.active?.canTogglePlaying ?? false + primary: true + + function onClicked(): void { + Players.active?.togglePlaying(); + } + } + + Control { + icon: "skip_next" + canUse: Players.active?.canGoNext ?? false + + function onClicked(): void { + Players.active?.next(); + } + } + } + } + + component Control: StyledRect { + id: control + + required property string icon + required property bool canUse + property int fontSize: Appearance.font.size.extraLarge + property int padding + property bool fill: true + property bool primary + function onClicked(): void { + } + + implicitWidth: Math.max(icon.implicitWidth, icon.implicitHeight) + padding * 2 + implicitHeight: implicitWidth + + radius: Appearance.rounding.full + color: primary && canUse ? Colours.palette.m3primary : "transparent" + + StateLayer { + disabled: !control.canUse + radius: parent.radius + color: control.primary ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + control.onClicked(); + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -font.pointSize * 0.02 + anchors.verticalCenterOffset: font.pointSize * 0.02 + + animate: true + fill: control.fill ? 1 : 0 + text: control.icon + color: control.canUse ? control.primary ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface : Colours.palette.m3outline + font.pointSize: control.fontSize + } + } +} |