feat: lock screen
This commit is contained in:
parent
7f2b5b4b6f
commit
2a652d549a
8 changed files with 675 additions and 0 deletions
|
|
@ -15,6 +15,7 @@ Singleton {
|
||||||
property alias osd: adapter.osd
|
property alias osd: adapter.osd
|
||||||
property alias session: adapter.session
|
property alias session: adapter.session
|
||||||
property alias winfo: adapter.winfo
|
property alias winfo: adapter.winfo
|
||||||
|
property alias lock: adapter.lock
|
||||||
property alias paths: adapter.paths
|
property alias paths: adapter.paths
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
|
|
@ -34,6 +35,7 @@ Singleton {
|
||||||
property JsonObject osd: OsdConfig {}
|
property JsonObject osd: OsdConfig {}
|
||||||
property JsonObject session: SessionConfig {}
|
property JsonObject session: SessionConfig {}
|
||||||
property JsonObject winfo: WInfoConfig {}
|
property JsonObject winfo: WInfoConfig {}
|
||||||
|
property JsonObject lock: LockConfig {}
|
||||||
property JsonObject paths: UserPaths {}
|
property JsonObject paths: UserPaths {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
config/LockConfig.qml
Normal file
12
config/LockConfig.qml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
JsonObject {
|
||||||
|
property JsonObject sizes: JsonObject {
|
||||||
|
property real border: 0.1
|
||||||
|
property int clockWidth: 800
|
||||||
|
property int clockHeight: 200
|
||||||
|
property int inputWidth: 600
|
||||||
|
property int inputHeight: 200
|
||||||
|
property int faceSize: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
216
modules/lock/Backgrounds.qml
Normal file
216
modules/lock/Backgrounds.qml
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool locked
|
||||||
|
|
||||||
|
readonly property real clockBottom: innerMask.anchors.margins + clockPath.height
|
||||||
|
readonly property real inputTop: innerMask.anchors.margins + inputPath.height
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: base
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colours.alpha(Config.border.colour, false)
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: mask
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: innerMask
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: root.locked ? root.height * Config.lock.sizes.border : 0
|
||||||
|
anchors.leftMargin: root.locked ? root.width * Config.lock.sizes.border : 0
|
||||||
|
anchors.rightMargin: root.locked ? root.width * Config.lock.sizes.border : 0
|
||||||
|
|
||||||
|
radius: Appearance.rounding.large * 2
|
||||||
|
|
||||||
|
Behavior on anchors.margins {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on anchors.rightMargin {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: base
|
||||||
|
maskEnabled: true
|
||||||
|
maskInverted: true
|
||||||
|
maskSource: mask
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Math.floor(innerMask.anchors.margins)
|
||||||
|
anchors.leftMargin: innerMask.anchors.leftMargin
|
||||||
|
anchors.rightMargin: innerMask.anchors.rightMargin
|
||||||
|
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: clockPath
|
||||||
|
|
||||||
|
readonly property int width: Config.lock.sizes.clockWidth
|
||||||
|
property real height: root.locked ? Config.lock.sizes.clockHeight : 0
|
||||||
|
|
||||||
|
readonly property real rounding: Appearance.rounding.large * 4
|
||||||
|
readonly property bool flatten: height < rounding * 2
|
||||||
|
readonly property real roundingY: flatten ? height / 2 : rounding
|
||||||
|
|
||||||
|
strokeWidth: -1
|
||||||
|
fillColor: Config.border.colour
|
||||||
|
|
||||||
|
startX: (innerMask.width - width) / 2 - rounding
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: clockPath.rounding
|
||||||
|
relativeY: clockPath.roundingY
|
||||||
|
radiusX: clockPath.rounding
|
||||||
|
radiusY: Math.min(clockPath.rounding, clockPath.height)
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: clockPath.height - clockPath.roundingY * 2
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: clockPath.rounding
|
||||||
|
relativeY: clockPath.roundingY
|
||||||
|
radiusX: clockPath.rounding
|
||||||
|
radiusY: Math.min(clockPath.rounding, clockPath.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: clockPath.width - clockPath.rounding * 2
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: clockPath.rounding
|
||||||
|
relativeY: -clockPath.roundingY
|
||||||
|
radiusX: clockPath.rounding
|
||||||
|
radiusY: Math.min(clockPath.rounding, clockPath.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: -(clockPath.height - clockPath.roundingY * 2)
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: clockPath.rounding
|
||||||
|
relativeY: -clockPath.roundingY
|
||||||
|
radiusX: clockPath.rounding
|
||||||
|
radiusY: Math.min(clockPath.rounding, clockPath.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on fillColor {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: inputPath
|
||||||
|
|
||||||
|
readonly property int width: Config.lock.sizes.inputWidth
|
||||||
|
property real height: root.locked ? Config.lock.sizes.inputHeight : 0
|
||||||
|
|
||||||
|
readonly property real rounding: Appearance.rounding.large * 2
|
||||||
|
readonly property bool flatten: height < rounding * 2
|
||||||
|
readonly property real roundingY: flatten ? height / 2 : rounding
|
||||||
|
|
||||||
|
strokeWidth: -1
|
||||||
|
fillColor: Config.border.colour
|
||||||
|
|
||||||
|
startX: (innerMask.width - width) / 2 - rounding
|
||||||
|
startY: Math.ceil(innerMask.height)
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: inputPath.rounding
|
||||||
|
relativeY: -inputPath.roundingY
|
||||||
|
radiusX: inputPath.rounding
|
||||||
|
radiusY: Math.min(inputPath.rounding, inputPath.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: -(inputPath.height - inputPath.roundingY * 2)
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: inputPath.rounding
|
||||||
|
relativeY: -inputPath.roundingY
|
||||||
|
radiusX: inputPath.rounding
|
||||||
|
radiusY: Math.min(inputPath.rounding, inputPath.height)
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: inputPath.width - inputPath.rounding * 2
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: inputPath.rounding
|
||||||
|
relativeY: inputPath.roundingY
|
||||||
|
radiusX: inputPath.rounding
|
||||||
|
radiusY: Math.min(inputPath.rounding, inputPath.height)
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: inputPath.height - inputPath.roundingY * 2
|
||||||
|
}
|
||||||
|
PathArc {
|
||||||
|
relativeX: inputPath.rounding
|
||||||
|
relativeY: inputPath.roundingY
|
||||||
|
radiusX: inputPath.rounding
|
||||||
|
radiusY: Math.min(inputPath.rounding, inputPath.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||||
|
}
|
||||||
|
}
|
||||||
56
modules/lock/Clock.qml
Normal file
56
modules/lock/Clock.qml
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool locked
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text: Time.format("HH")
|
||||||
|
color: Colours.palette.m3secondary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge * 4
|
||||||
|
font.family: Appearance.font.family.mono
|
||||||
|
font.weight: 800
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text: ":"
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge * 4
|
||||||
|
font.family: Appearance.font.family.mono
|
||||||
|
font.weight: 800
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text: Time.format("mm")
|
||||||
|
color: Colours.palette.m3secondary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge * 4
|
||||||
|
font.family: Appearance.font.family.mono
|
||||||
|
font.weight: 800
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: Appearance.padding.large * 3
|
||||||
|
|
||||||
|
text: Time.format("dddd, d MMMM yyyy")
|
||||||
|
color: Colours.palette.m3tertiary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
font.family: Appearance.font.family.mono
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
254
modules/lock/Input.qml
Normal file
254
modules/lock/Input.qml
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import "root:/utils"
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Pam
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property WlSessionLockSurface lock
|
||||||
|
|
||||||
|
property string passwordBuffer
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Appearance.padding.large * 3
|
||||||
|
Layout.maximumWidth: Config.lock.sizes.inputWidth - Appearance.rounding.large * 2
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
StyledClippingRect {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
implicitWidth: Config.lock.sizes.faceSize
|
||||||
|
implicitHeight: Config.lock.sizes.faceSize
|
||||||
|
|
||||||
|
radius: Appearance.rounding.large
|
||||||
|
color: Colours.palette.m3surfaceContainer
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
text: "person"
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Config.lock.sizes.faceSize / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
CachingImage {
|
||||||
|
anchors.fill: parent
|
||||||
|
path: `${Paths.home}/.face`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Welcome back, %1").arg(Quickshell.env("USER"))
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
font.weight: 500
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Logging in to %1").arg(Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP"))
|
||||||
|
color: Colours.palette.m3tertiary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: charList.implicitWidth + Appearance.padding.large * 2
|
||||||
|
Layout.preferredHeight: Appearance.font.size.normal + Appearance.padding.large * 2
|
||||||
|
|
||||||
|
focus: true
|
||||||
|
color: Colours.palette.m3surfaceContainer
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (pam.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
|
placeholder.animate = false;
|
||||||
|
pam.start();
|
||||||
|
} else if (event.key === Qt.Key_Backspace) {
|
||||||
|
if (event.modifiers & Qt.ControlModifier) {
|
||||||
|
charList.implicitWidth = charList.implicitWidth; // Break binding
|
||||||
|
root.passwordBuffer = "";
|
||||||
|
} else {
|
||||||
|
root.passwordBuffer = root.passwordBuffer.slice(0, -1);
|
||||||
|
}
|
||||||
|
} else if ("abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
|
||||||
|
charList.bindImWidth();
|
||||||
|
root.passwordBuffer += event.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PamContext {
|
||||||
|
id: pam
|
||||||
|
|
||||||
|
onResponseRequiredChanged: {
|
||||||
|
if (!responseRequired)
|
||||||
|
return;
|
||||||
|
|
||||||
|
respond(root.passwordBuffer);
|
||||||
|
charList.implicitWidth = charList.implicitWidth; // Break binding
|
||||||
|
root.passwordBuffer = "";
|
||||||
|
placeholder.animate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCompleted: res => {
|
||||||
|
if (res === PamResult.Success)
|
||||||
|
return root.lock.unlock();
|
||||||
|
|
||||||
|
if (res === PamResult.Error)
|
||||||
|
placeholder.pamState = "error";
|
||||||
|
else if (res === PamResult.MaxTries)
|
||||||
|
placeholder.pamState = "max";
|
||||||
|
else if (res === PamResult.Failed)
|
||||||
|
placeholder.pamState = "fail";
|
||||||
|
|
||||||
|
placeholderDelay.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: placeholderDelay
|
||||||
|
|
||||||
|
interval: 3000
|
||||||
|
onTriggered: placeholder.pamState = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: placeholder
|
||||||
|
|
||||||
|
property string pamState
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
text: {
|
||||||
|
if (pam.active)
|
||||||
|
return qsTr("Loading...");
|
||||||
|
if (pamState === "error")
|
||||||
|
return qsTr("An error occured");
|
||||||
|
if (pamState === "max")
|
||||||
|
return qsTr("You have reached the maximum number of tries");
|
||||||
|
if (pamState === "fail")
|
||||||
|
return qsTr("Incorrect password");
|
||||||
|
return qsTr("Enter your password");
|
||||||
|
}
|
||||||
|
|
||||||
|
animate: true
|
||||||
|
color: pam.active ? Colours.palette.m3secondary : pamState ? Colours.palette.m3error : Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
|
||||||
|
opacity: root.passwordBuffer ? 0 : 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: charList
|
||||||
|
|
||||||
|
function bindImWidth(): void {
|
||||||
|
imWidthBehavior.enabled = false;
|
||||||
|
implicitWidth = Qt.binding(() => Math.min(count * (Appearance.font.size.normal + spacing) - spacing, Config.lock.sizes.inputWidth - Appearance.rounding.large * 2 - Appearance.padding.large * 5));
|
||||||
|
imWidthBehavior.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
implicitWidth: Math.min(count * (Appearance.font.size.normal + spacing) - spacing, Config.lock.sizes.inputWidth - Appearance.rounding.large * 2 - Appearance.padding.large * 5)
|
||||||
|
implicitHeight: Appearance.font.size.normal
|
||||||
|
|
||||||
|
orientation: Qt.Horizontal
|
||||||
|
spacing: Appearance.spacing.small / 2
|
||||||
|
|
||||||
|
model: ScriptModel {
|
||||||
|
values: root.passwordBuffer.split("")
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: StyledRect {
|
||||||
|
id: ch
|
||||||
|
|
||||||
|
implicitWidth: Appearance.font.size.normal
|
||||||
|
implicitHeight: Appearance.font.size.normal
|
||||||
|
|
||||||
|
color: Colours.palette.m3onSurface
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
scale: 0.5
|
||||||
|
Component.onCompleted: {
|
||||||
|
opacity = 1;
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
ListView.onRemove: removeAnim.start()
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: removeAnim
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
target: ch
|
||||||
|
property: "ListView.delayRemove"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
target: ch
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: ch
|
||||||
|
property: "scale"
|
||||||
|
to: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: ch
|
||||||
|
property: "ListView.delayRemove"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
id: imWidthBehavior
|
||||||
|
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Anim: NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
36
modules/lock/Lock.qml
Normal file
36
modules/lock/Lock.qml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import "root:/widgets"
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
WlSessionLock {
|
||||||
|
id: lock
|
||||||
|
|
||||||
|
LockSurface {
|
||||||
|
lock: lock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomShortcut {
|
||||||
|
name: "lock"
|
||||||
|
description: "Lock the current session"
|
||||||
|
onPressed: lock.locked = true
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomShortcut {
|
||||||
|
name: "unlock"
|
||||||
|
description: "Unlock the current session"
|
||||||
|
onPressed: lock.locked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "lock"
|
||||||
|
|
||||||
|
function lock(): void {
|
||||||
|
lock.locked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
modules/lock/LockSurface.qml
Normal file
97
modules/lock/LockSurface.qml
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
WlSessionLockSurface {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property WlSessionLock lock
|
||||||
|
|
||||||
|
property bool locked
|
||||||
|
|
||||||
|
function unlock(): void {
|
||||||
|
locked = false;
|
||||||
|
background.opacity = 0;
|
||||||
|
animDelay.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: locked = true
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: animDelay
|
||||||
|
|
||||||
|
interval: Appearance.anim.durations.large
|
||||||
|
onTriggered: root.lock.locked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreencopyView {
|
||||||
|
id: screencopy
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
captureSource: root.screen
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
id: background
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
source: screencopy
|
||||||
|
autoPaddingEnabled: false
|
||||||
|
blurEnabled: true
|
||||||
|
blur: root.locked ? 1 : 0
|
||||||
|
blurMax: 64
|
||||||
|
blurMultiplier: 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on blur {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Backgrounds {
|
||||||
|
id: backgrounds
|
||||||
|
|
||||||
|
locked: root.locked
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: source
|
||||||
|
source: backgrounds
|
||||||
|
shadowEnabled: true
|
||||||
|
blurMax: 15
|
||||||
|
shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7)
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: -backgrounds.clockBottom
|
||||||
|
|
||||||
|
locked: root.locked
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.bottom
|
||||||
|
anchors.topMargin: -backgrounds.inputTop
|
||||||
|
|
||||||
|
lock: root
|
||||||
|
}
|
||||||
|
|
||||||
|
component Anim: NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,12 +4,14 @@ import "modules"
|
||||||
import "modules/drawers"
|
import "modules/drawers"
|
||||||
import "modules/background"
|
import "modules/background"
|
||||||
import "modules/areapicker"
|
import "modules/areapicker"
|
||||||
|
import "modules/lock"
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
Background {}
|
Background {}
|
||||||
Drawers {}
|
Drawers {}
|
||||||
AreaPicker {}
|
AreaPicker {}
|
||||||
|
Lock {}
|
||||||
|
|
||||||
Shortcuts {}
|
Shortcuts {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue