diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2025-09-05 23:31:35 +0200 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2025-09-05 23:31:35 +0200 |
commit | 14d4d05acc235ab7033316d16530783c90e95faa (patch) | |
tree | 2a6e0953cd5f4e4419274178c8a44a34456ab32c /accounts/gkleen@sif/shell/quickshell/LockSurface.qml | |
parent | 02dbc3d9260fa1137e8ebc99ad439fc555d81fd2 (diff) | |
download | nixos-14d4d05acc235ab7033316d16530783c90e95faa.tar nixos-14d4d05acc235ab7033316d16530783c90e95faa.tar.gz nixos-14d4d05acc235ab7033316d16530783c90e95faa.tar.bz2 nixos-14d4d05acc235ab7033316d16530783c90e95faa.tar.xz nixos-14d4d05acc235ab7033316d16530783c90e95faa.zip |
...quickshell
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell/LockSurface.qml')
-rw-r--r-- | accounts/gkleen@sif/shell/quickshell/LockSurface.qml | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell/LockSurface.qml b/accounts/gkleen@sif/shell/quickshell/LockSurface.qml new file mode 100644 index 00000000..18698725 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/LockSurface.qml | |||
@@ -0,0 +1,223 @@ | |||
1 | import Quickshell.Widgets | ||
2 | import QtQuick.Effects | ||
3 | import QtQuick.Layouts | ||
4 | import QtQuick | ||
5 | import QtQuick.Controls | ||
6 | import QtQuick.Controls.Fusion | ||
7 | import qs.Services | ||
8 | import QtQml | ||
9 | |||
10 | Item { | ||
11 | id: lockSurface | ||
12 | |||
13 | property var screen | ||
14 | property list<var> messages: [] | ||
15 | property bool responseRequired: false | ||
16 | property bool responseVisible: false | ||
17 | property string currentText: "" | ||
18 | property bool authRunning: false | ||
19 | |||
20 | signal response(string responseText) | ||
21 | |||
22 | anchors.fill: parent | ||
23 | |||
24 | Item { | ||
25 | id: background | ||
26 | |||
27 | anchors.fill: parent | ||
28 | |||
29 | property Img current: one | ||
30 | property string source: selector.selected | ||
31 | |||
32 | WallpaperSelector { | ||
33 | id: selector | ||
34 | seed: lockSurface.screen?.name || "" | ||
35 | } | ||
36 | |||
37 | onSourceChanged: { | ||
38 | if (!source) | ||
39 | current = null; | ||
40 | else if (current === one) | ||
41 | two.update() | ||
42 | else | ||
43 | one.update() | ||
44 | } | ||
45 | |||
46 | Img { id: one } | ||
47 | Img { id: two } | ||
48 | |||
49 | component Img: Item { | ||
50 | id: img | ||
51 | |||
52 | property string source | ||
53 | |||
54 | function update() { | ||
55 | source = background.source || "" | ||
56 | } | ||
57 | |||
58 | anchors.fill: parent | ||
59 | |||
60 | Image { | ||
61 | id: imageSource | ||
62 | |||
63 | source: img.source | ||
64 | sourceSize: Qt.size(parent.width, parent.height) | ||
65 | fillMode: Image.PreserveAspectCrop | ||
66 | smooth: true | ||
67 | visible: false | ||
68 | asynchronous: true | ||
69 | cache: false | ||
70 | |||
71 | onStatusChanged: { | ||
72 | if (status === Image.Ready) { | ||
73 | background.current = img | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | MultiEffect { | ||
79 | id: imageEffect | ||
80 | |||
81 | source: imageSource | ||
82 | anchors.fill: parent | ||
83 | blurEnabled: true | ||
84 | blur: 1 | ||
85 | blurMax: 64 | ||
86 | blurMultiplier: 2 | ||
87 | |||
88 | opacity: 0 | ||
89 | |||
90 | states: State { | ||
91 | name: "visible" | ||
92 | when: background.current === img | ||
93 | |||
94 | PropertyChanges { | ||
95 | imageEffect.opacity: 1 | ||
96 | } | ||
97 | StateChangeScript { | ||
98 | name: "unloadOther" | ||
99 | script: { | ||
100 | if (img === one) | ||
101 | two.source = "" | ||
102 | if (img === two) | ||
103 | one.source = "" | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | transitions: Transition { | ||
109 | SequentialAnimation { | ||
110 | NumberAnimation { | ||
111 | target: imageEffect | ||
112 | properties: "opacity" | ||
113 | duration: 5000 | ||
114 | easing.type: Easing.OutCubic | ||
115 | } | ||
116 | ScriptAction { | ||
117 | scriptName: "unloadOther" | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | Item { | ||
126 | anchors { | ||
127 | top: lockSurface.top | ||
128 | left: lockSurface.left | ||
129 | right: lockSurface.right | ||
130 | } | ||
131 | |||
132 | implicitWidth: lockSurface.width | ||
133 | implicitHeight: 21 | ||
134 | |||
135 | Rectangle { | ||
136 | anchors.fill: parent | ||
137 | color: Qt.rgba(0, 0, 0, 0.75) | ||
138 | } | ||
139 | |||
140 | Clock { | ||
141 | anchors.centerIn: parent | ||
142 | calendarPopup: false | ||
143 | } | ||
144 | } | ||
145 | |||
146 | WrapperRectangle { | ||
147 | id: unlockUi | ||
148 | |||
149 | Keys.onPressed: event => { | ||
150 | if (!lockSurface.authRunning) { | ||
151 | event.accepted = true; | ||
152 | lockSurface.authRunning = true; | ||
153 | } | ||
154 | } | ||
155 | focus: !passwordBox.visible | ||
156 | |||
157 | visible: lockSurface.authRunning | ||
158 | |||
159 | color: Qt.rgba(0, 0, 0, 0.75) | ||
160 | margin: 8 | ||
161 | |||
162 | anchors.centerIn: parent | ||
163 | |||
164 | ColumnLayout { | ||
165 | spacing: 4 | ||
166 | |||
167 | BusyIndicator { | ||
168 | visible: running | ||
169 | running: !Array.from(lockSurface.messages).length && !lockSurface.responseRequired | ||
170 | } | ||
171 | |||
172 | Repeater { | ||
173 | model: lockSurface.messages | ||
174 | |||
175 | Text { | ||
176 | required property var modelData | ||
177 | |||
178 | font.pointSize: 10 | ||
179 | font.family: "Fira Sans" | ||
180 | color: modelData.error ? "#f28a21" : "#ffffff" | ||
181 | |||
182 | text: String(modelData.text).trim() | ||
183 | |||
184 | Layout.fillWidth: true | ||
185 | horizontalAlignment: Text.AlignHCenter | ||
186 | } | ||
187 | } | ||
188 | |||
189 | TextField { | ||
190 | id: passwordBox | ||
191 | |||
192 | visible: lockSurface.responseRequired | ||
193 | echoMode: lockSurface.responseVisible ? TextInput.Normal : TextInput.Password | ||
194 | inputMethodHints: Qt.ImhSensitiveData | ||
195 | |||
196 | onTextChanged: lockSurface.currentText = passwordBox.text | ||
197 | onAccepted: { | ||
198 | passwordBox.readOnly = true; | ||
199 | lockSurface.response(lockSurface.currentText); | ||
200 | } | ||
201 | |||
202 | Connections { | ||
203 | target: lockSurface | ||
204 | function onCurrentTextChanged() { | ||
205 | passwordBox.text = lockSurface.currentText | ||
206 | } | ||
207 | } | ||
208 | Connections { | ||
209 | target: lockSurface | ||
210 | function onResponseRequiredChanged() { | ||
211 | if (lockSurface.responseRequired) | ||
212 | passwordBox.readOnly = false; | ||
213 | passwordBox.focus = true; | ||
214 | passwordBox.selectAll(); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | Layout.topMargin: 4 | ||
219 | Layout.fillWidth: true | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | } | ||