Huge quickshell progress dump

Was requested
This commit is contained in:
outfoxxed 2024-06-17 00:49:34 -07:00
parent 57d9f9a72e
commit 945793973e
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
42 changed files with 2140 additions and 142 deletions

View file

@ -0,0 +1,149 @@
pragma Singleton
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import ".."
import "../.."
Singleton {
id: root
function init() {}
property bool locked: false;
onLockedChanged: {
if (locked) {
lockContextLoader.active = true;
lock.locked = true;
} else {
lockClearTimer.start();
workspaceUnlockAnimation();
}
}
Timer {
id: lockClearTimer
interval: 600
onTriggered: {
lock.locked = false;
lockContextLoader.active = false;
}
}
property var oldWorkspaces: ({});
function workspaceLockAnimation() {
const focusedMonitor = Hyprland.focusedMonitor.id;
Hyprland.monitors.values.forEach(monitor => {
if (monitor.activeWorkspace) {
root.oldWorkspaces[monitor.id] = monitor.activeWorkspace.id;
}
Hyprland.dispatch(`workspace name:lock_${monitor.name}`);
});
Hyprland.dispatch(`focusmonitor ${focusedMonitor}`);
}
function workspaceUnlockAnimation() {
const focusedMonitor = Hyprland.focusedMonitor.id;
Hyprland.monitors.values.forEach(monitor => {
const workspace = root.oldWorkspaces[monitor.id];
if (workspace) Hyprland.dispatch(`workspace ${workspace}`);
});
Hyprland.dispatch(`focusmonitor ${focusedMonitor}`);
root.oldWorkspaces = ({});
}
Shortcut {
name: "lock"
onPressed: {
if (root.locked) root.locked = false;
else root.locked = true;
}
}
LazyLoader {
id: lockContextLoader
LockContext {
onUnlocked: root.locked = false;
}
}
WlSessionLock {
id: lock
onSecureChanged: {
if (secure) {
Qt.callLater(() => root.workspaceLockAnimation());
}
}
WlSessionLockSurface {
id: lockSurface
color: "transparent"
// Ensure nothing spawns in the workspace behind the transparent lock
// by filling in the background after animations complete.
Rectangle {
anchors.fill: parent
color: "gray"
visible: backgroundImage.visible
}
BackgroundImage {
id: backgroundImage
anchors.fill: parent
screen: lockSurface.screen
visible: !lockAnim.running
asynchronous: true
}
LockContent {
id: lockContent
context: lockContextLoader.item;
visible: false
width: lockSurface.width
height: lockSurface.height
}
NumberAnimation {
id: lockAnim
target: lockContent
property: "y"
to: 0
duration: 600
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.0, 0.75, 0.15, 1.0, 1.0, 1.0]
}
onVisibleChanged: {
if (visible) {
lockContent.y = -lockSurface.height
console.log(`y ${lockContent.y}`)
lockContent.visible = true;
lockAnim.running = true;
}
}
Connections {
target: root
function onLockedChanged() {
if (!locked) {
lockAnim.to = -lockSurface.height
lockAnim.running = true;
}
}
}
}
}
}

View file

@ -0,0 +1,50 @@
import QtQuick
import "root:."
Item {
id: root
implicitHeight: 75
implicitWidth: showProgress * 0.1
signal clicked();
property string icon;
property bool show: true;
property int showProgress: show ? 1000 : 0
Behavior on showProgress {
NumberAnimation {
duration: 100
easing.type: Easing.OutQuad
}
}
MouseArea {
id: mouseArea
implicitWidth: 75
implicitHeight: 75
hoverEnabled: true
y: -(height + 30) * (1.0 - showProgress * 0.001)
x: 12.5 - 50 * (1.0 - showProgress * 0.001)
Component.onCompleted: clicked.connect(root.clicked);
Rectangle {
anchors.fill: parent
radius: 5
color: ShellGlobals.interpolateColors(hoverColorInterp * 0.001, ShellGlobals.colors.widget, ShellGlobals.colors.widgetActive);
border.width: 1
border.color: ShellGlobals.colors.widgetOutline
property int hoverColorInterp: mouseArea.containsMouse || mouseArea.pressed ? 1000 : 0;
Behavior on hoverColorInterp { SmoothedAnimation { velocity: 10000 } }
Image {
anchors.fill: parent
anchors.margins: 15
source: root.icon
}
}
}
}

View file

@ -0,0 +1,113 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import ".."
Item {
id: root
required property LockContext context;
property real focusAnim: focusAnimInternal * 0.001
property int focusAnimInternal: Window.active ? 1000 : 0
Behavior on focusAnimInternal { SmoothedAnimation { velocity: 5000 } }
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height / 2 + textBox.height
id: sep
implicitHeight: 6
implicitWidth: 800
radius: height / 2
color: ShellGlobals.colors.widget
}
ColumnLayout {
implicitWidth: sep.implicitWidth
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: sep.top
spacing: 0
Text {
id: timeText
Layout.alignment: Qt.AlignHCenter
font {
pointSize: 120
hintingPreference: Font.PreferFullHinting
family: "Noto Sans"
}
color: "white"
renderType: Text.NativeRendering
text: {
const hours = ShellGlobals.time.getHours().toString().padStart(2, '0');
const minutes = ShellGlobals.time.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
}
}
Item {
Layout.alignment: Qt.AlignHCenter
implicitHeight: childrenRect.height * focusAnim
implicitWidth: sep.implicitWidth
clip: true
TextInput {
id: textBox
focus: true
width: parent.width
color: enabled ?
root.context.failed ? "#ffa0a0" : "white"
: "#80ffffff";
font.pointSize: 24
horizontalAlignment: TextInput.AlignHCenter
echoMode: TextInput.Password
inputMethodHints: Qt.ImhSensitiveData
onTextChanged: root.context.currentText = text;
Window.onActiveChanged: {
if (Window.active) {
text = root.context.currentText;
}
}
onAccepted: {
if (text != "") root.context.tryUnlock();
}
enabled: !root.context.isUnlocking;
}
}
}
Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: sep.bottom
implicitHeight: (childrenRect.height + 30) * focusAnim
implicitWidth: sep.implicitWidth
clip: true
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.topMargin: 50
spacing: 0
LockButton {
icon: "root:icons/monitor.svg"
onClicked: root.context.dpms();
}
LockButton {
icon: "root:icons/pause.svg"
show: context.mediaPlaying;
onClicked: root.context.pauseMedia();
}
}
}
}

View file

@ -0,0 +1,57 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import Quickshell.Services.Mpris
Scope {
id: root
signal unlocked();
property string currentText: "";
readonly property alias isUnlocking: pamtester.running;
property bool failed: false;
onCurrentTextChanged: failed = false;
readonly property bool mediaPlaying: Mpris.players.values.some(player => {
return player.playbackState === MprisPlaybackState.Playing && player.canPause;
});
function pauseMedia() {
Mpris.players.values.forEach(player => {
if (player.playbackState === MprisPlaybackState.Playing && player.canPause) {
player.playbackState = MprisPlaybackState.Paused;
}
});
}
function dpms() {
Hyprland.dispatch(`dpms`);
}
Process {
id: pamtester
property bool failed: true
command: ["pamtester", "login", Quickshell.env("USER"), "authenticate"]
onStarted: this.write(`${currentText}\n`)
stdout: SplitParser {
// fails go to stderr
onRead: pamtester.failed = false
}
onExited: {
if (failed) {
root.failed = true;
} else {
root.unlocked();
}
}
}
function tryUnlock() {
pamtester.running = true;
}
}