import Quickshell.Widgets import QtQuick.Effects import QtQuick.Layouts import QtQuick import QtQuick.Controls import QtQuick.Controls.Fusion import qs.Services import QtQml Item { id: lockSurface property var screen property list messages: [] property bool responseRequired: false property bool responseVisible: false property string currentText: "" property bool authRunning: false signal response(string responseText) anchors.fill: parent Item { id: background anchors.fill: parent property Img current: one property string source: selector.selected WallpaperSelector { id: selector seed: lockSurface.screen?.name || "" } onSourceChanged: { if (!source) current = null; else if (current === one) two.update() else one.update() } Img { id: one } Img { id: two } component Img: Item { id: img property string source function update() { source = background.source || "" } anchors.fill: parent Image { id: imageSource source: img.source sourceSize: Qt.size(parent.width, parent.height) fillMode: Image.PreserveAspectCrop smooth: true visible: false asynchronous: true cache: false onStatusChanged: { if (status === Image.Ready) { background.current = img } } } MultiEffect { id: imageEffect source: imageSource anchors.fill: parent blurEnabled: true blur: 1 blurMax: 64 blurMultiplier: 2 opacity: 0 states: State { name: "visible" when: background.current === img PropertyChanges { imageEffect.opacity: 1 } StateChangeScript { name: "unloadOther" script: { if (img === one) two.source = "" if (img === two) one.source = "" } } } transitions: Transition { SequentialAnimation { NumberAnimation { target: imageEffect properties: "opacity" duration: 5000 easing.type: Easing.OutCubic } ScriptAction { scriptName: "unloadOther" } } } } } } Item { anchors { top: lockSurface.top left: lockSurface.left right: lockSurface.right } implicitWidth: lockSurface.width implicitHeight: 21 Rectangle { anchors.fill: parent color: Qt.rgba(0, 0, 0, 0.75) } Clock { anchors.centerIn: parent calendarPopup: false } } WrapperRectangle { id: unlockUi Keys.onPressed: event => { if (!lockSurface.authRunning) { event.accepted = true; lockSurface.authRunning = true; } } focus: !passwordBox.visible visible: lockSurface.authRunning color: Qt.rgba(0, 0, 0, 0.75) margin: 8 anchors.centerIn: parent ColumnLayout { spacing: 4 BusyIndicator { visible: running running: !Array.from(lockSurface.messages).length && !lockSurface.responseRequired } Repeater { model: lockSurface.messages Text { required property var modelData font.pointSize: 10 font.family: "Fira Sans" color: modelData.error ? "#f28a21" : "#ffffff" text: String(modelData.text).trim() Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter } } TextField { id: passwordBox visible: lockSurface.responseRequired echoMode: lockSurface.responseVisible ? TextInput.Normal : TextInput.Password inputMethodHints: Qt.ImhSensitiveData onTextChanged: lockSurface.currentText = passwordBox.text onAccepted: { passwordBox.readOnly = true; lockSurface.response(lockSurface.currentText); } Connections { target: lockSurface function onCurrentTextChanged() { passwordBox.text = lockSurface.currentText } } Connections { target: lockSurface function onResponseRequiredChanged() { if (lockSurface.responseRequired) passwordBox.readOnly = false; passwordBox.focus = true; passwordBox.selectAll(); } } Layout.topMargin: 4 Layout.fillWidth: true } } } }