waffles: add lock screen, fix ctrl alt del screen for light mode

This commit is contained in:
end-4
2025-12-09 23:05:48 +01:00
parent bfe97c1c05
commit fdbe39d744
14 changed files with 441 additions and 59 deletions
@@ -86,7 +86,7 @@ Item {
}
WindowDialogButtonRow {
Layout.bottomMargin: 10 // I honestly don't know why this is necessary
Item {
Layout.fillWidth: true
}
@@ -0,0 +1,324 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.common.panels.lock
import qs.modules.waffle.looks
import qs.modules.waffle.sessionScreen as SessionScreen
LockScreen {
id: root
property bool passwordView: false
lockSurface: Item {
id: lockSurfaceItem
Component.onCompleted: {
root.passwordView = false;
lockSurfaceItem.forceActiveFocus();
}
Keys.onPressed: {
root.passwordView = true;
}
Image {
id: bg
z: 0
anchors.fill: parent
sourceSize: Qt.size(lockSurfaceItem.width, lockSurfaceItem.height)
source: Config.options.background.wallpaperPath
fillMode: Image.PreserveAspectCrop
}
GaussianBlur {
z: 1
anchors.fill: parent
source: bg
radius: 100
samples: radius * 2 + 1
scale: root.passwordView ? 1.1 : 1
opacity: root.passwordView ? 1 : 0
Behavior on opacity {
animation: Looks.transition.opacity.createObject(this)
}
Behavior on scale {
NumberAnimation {
duration: 400
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
}
}
Interactables {
z: 2
anchors.fill: parent
}
}
component Interactables: Rectangle {
id: interactables
color: ColorUtils.transparentize("#000000", 0.8)
// Button {
// onClicked: {
// root.context.unlocked(LockContext.ActionEnum.Unlock);
// GlobalStates.screenLocked = false;
// }
// text: "woah it doesnt work let me out pls uwu colon three"
// }
ClockTextGroup {
visible: !root.passwordView
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: interactables.height * 0.1
}
}
PasswordGroup {
visible: root.passwordView
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
}
RowLayout {
visible: !root.passwordView
anchors {
bottom: parent.bottom
right: parent.right
bottomMargin: 21
rightMargin: 31
}
IconIndicator {
baseIcon: "wifi-1"
icon: WIcons.internetIcon
}
IconIndicator {
baseIcon: WIcons.batteryIcon
icon: WIcons.batteryLevelIcon
}
}
RowLayout {
visible: root.passwordView
anchors {
bottom: parent.bottom
right: parent.right
bottomMargin: 21
rightMargin: 31
}
SessionScreen.PowerButton {
id: powerButton
}
}
}
component IconIndicator: Item {
id: iconIndicator
required property string baseIcon
required property string icon
default property alias data: iconWidget.data
implicitWidth: 40
implicitHeight: 40
FluentIcon {
id: iconWidget
anchors.centerIn: parent
icon: iconIndicator.baseIcon
color: Looks.darkColors.inactiveIcon
implicitSize: 20
FluentIcon {
anchors.fill: parent
icon: iconIndicator.icon
}
}
}
component ClockTextGroup: Column {
id: clockTextGroup
spacing: -3
WText {
anchors.horizontalCenter: parent.horizontalCenter
color: Looks.darkColors.fg
font.pixelSize: 133
font.weight: Looks.font.weight.strong
text: {
// Don't take am/pm
// Match groups of digits separated by non-digit chars (e.g., "12:34", "12.34", "12-34")
let match = DateTime.time.match(/(\d{1,2})\D+(\d{2})/);
return match ? `${match[1]}${DateTime.time.match(/\D+/)[0]}${match[2]}` : DateTime.time;
}
}
WText {
id: dateLabel
color: Looks.darkColors.fg
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 28
font.weight: Looks.font.weight.strong
text: DateTime.collapsedCalendarFormat
}
}
component PasswordGroup: ColumnLayout {
id: passwordGroup
spacing: 15
WUserAvatar {
Layout.alignment: Qt.AlignHCenter
sourceSize: Qt.size(192, 192)
}
WText {
Layout.alignment: Qt.AlignHCenter
text: SystemInfo.username
color: Looks.darkColors.fg
font.pixelSize: 26
font.weight: Looks.font.weight.strong
}
Rectangle {
id: passwordInputWrapper
Layout.topMargin: 10
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 132
color: "transparent"
implicitWidth: 296
implicitHeight: 36
border.width: 2
border.color: Looks.applyContentTransparency(Looks.darkColors.bg1Border)
radius: Looks.radius.medium
Rectangle {
id: passwordInputBackground
anchors.fill: parent
anchors.margins: 2
radius: Looks.radius.small + 1
color: passwordInput.focus ? Looks.applyBackgroundTransparency(Looks.darkColors.bg1Base) : Looks.applyContentTransparency(Looks.darkColors.bg1)
RowLayout {
anchors.fill: parent
anchors.margins: 6
spacing: 3
WTextInput {
id: passwordInput
Layout.fillHeight: true
Layout.fillWidth: true
verticalAlignment: TextInput.AlignVCenter
inputMethodHints: Qt.ImhSensitiveData
echoMode: passwordVisibilityButton.pressed ? TextInput.Normal : TextInput.Password
color: Looks.darkColors.fg
font.pixelSize: 12
WText {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
visible: passwordInput.text.length === 0
text: Translation.tr("Password")
font.pixelSize: Looks.font.pixelSize.large
color: Looks.darkColors.fg
opacity: 0.8
}
onTextChanged: root.context.currentText = this.text
onAccepted: {
root.context.tryUnlock();
}
Connections {
target: root.context
function onCurrentTextChanged() {
passwordInput.text = root.context.currentText;
}
}
Connections {
target: root
function onPasswordViewChanged() {
passwordInput.forceActiveFocus();
}
}
Keys.onPressed: event => {
root.context.resetClearTimer();
}
}
PasswordBoxButton {
id: passwordVisibilityButton
property bool passwordVisible: false
onPressed: passwordVisible = true
onReleased: passwordVisible = false
icon.name: passwordVisible ? "eye-off" : "eye"
}
PasswordBoxButton {
onClicked: {
root.context.tryUnlock();
}
icon.name: "arrow-right"
}
}
}
Rectangle {
id: activeIndicatorLine
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
implicitHeight: 2
color: passwordInput.focus ? Looks.colors.accent : Looks.applyContentTransparency(Looks.darkColors.bg2Border)
}
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: passwordInputWrapper.width
height: passwordInputWrapper.height
radius: passwordInputWrapper.radius
}
}
}
Item {}
}
component PasswordBoxButton: WButton {
id: pwBoxBtn
implicitWidth: 28
implicitHeight: 22
property color colBackground: ColorUtils.transparentize(Looks.darkColors.bg1)
property color colBackgroundHover: ColorUtils.transparentize(Looks.darkColors.bg2Hover)
property color colBackgroundActive: ColorUtils.transparentize(Looks.darkColors.bg2Active)
fgColor: Looks.darkColors.fg
checked: hovered
contentItem: Item {
FluentIcon {
color: pwBoxBtn.fgColor
anchors.centerIn: parent
icon: pwBoxBtn.icon.name
implicitSize: 16
}
}
}
}
@@ -155,6 +155,11 @@ Singleton {
property real larger: 15
property real xlarger: 17
}
property QtObject variableAxes: QtObject {
property var ui: ({
"wdth": 25
})
}
}
transition: QtObject {
@@ -14,6 +14,9 @@ Menu {
property bool downDirection: false
property bool hasIcons: false // TODO: implement
property color color: Looks.colors.bg1Base
property alias backgroundPane: bgPane
implicitWidth: background.implicitWidth + margins * 2
implicitHeight: background.implicitHeight + margins * 2
margins: 10
@@ -58,7 +61,7 @@ Menu {
bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin
}
contentItem: Rectangle {
color: Looks.colors.bg1Base
color: root.color
implicitWidth: menuListView.implicitWidth + root.padding * 2
implicitHeight: root.contentItem.implicitHeight + root.padding * 2
}
@@ -12,6 +12,7 @@ Text {
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular
variableAxes: Looks.font.variableAxes.ui
}
linkColor: Looks.colors.link
@@ -11,6 +11,10 @@ TextField {
verticalAlignment: Text.AlignVCenter
color: Looks.colors.fg
palette {
active: Looks.colors.accent
}
font {
hintingPreference: Font.PreferDefaultHinting
family: Looks.font.family.ui
@@ -0,0 +1,76 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import qs.modules.waffle.looks
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
WSessionScreenTextButton {
id: root
implicitWidth: 40
implicitHeight: 40
focusRingRadius: Looks.radius.large
colBackground: ColorUtils.transparentize(Looks.darkColors.bg2)
colBackgroundHover: Looks.applyContentTransparency(Looks.darkColors.bg2Hover)
colBackgroundActive: Looks.applyContentTransparency(Looks.darkColors.bg2Active)
property color color: {
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
background: Rectangle {
id: background
radius: Looks.radius.medium
color: root.color
}
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
implicitSize: 20
icon: "power"
color: root.fgColor
}
}
onClicked: {
powerMenu.visible = !powerMenu.visible;
}
WMenu {
id: powerMenu
x: -powerMenu.implicitWidth / 2 + root.implicitWidth / 2
y: -powerMenu.implicitHeight
color: Looks.darkColors.bg1Base
Component.onCompleted: {
powerMenu.backgroundPane.borderColor = Looks.applyContentTransparency(Looks.darkColors.bg2Border);
}
delegate: WMenuItem {
id: menuItemDelegate
colBackground: ColorUtils.transparentize(Looks.darkColors.bg1Base)
colBackgroundHover: Looks.applyContentTransparency(Looks.darkColors.bg2Hover)
colBackgroundActive: Looks.applyContentTransparency(Looks.darkColors.bg2Active)
colForeground: Looks.darkColors.fg
}
Action {
icon.name: "power"
text: Translation.tr("Shut down")
onTriggered: Session.poweroff()
}
Action {
icon.name: "arrow-counterclockwise"
text: Translation.tr("Restart")
onTriggered: Session.reboot()
}
}
}
@@ -8,7 +8,6 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
Item {
id: root
@@ -94,63 +93,13 @@ Item {
}
}
component PowerButton: WSessionScreenTextButton {
id: root
implicitWidth: 40
implicitHeight: 40
focusRingRadius: Looks.radius.large
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
property color color: {
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
background: Rectangle {
id: background
radius: Looks.radius.medium
color: root.color
}
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
implicitSize: 20
icon: "power"
}
}
onClicked: {
powerMenu.visible = !powerMenu.visible;
}
WMenu {
id: powerMenu
x: -powerMenu.implicitWidth / 2 + root.implicitWidth / 2
y: -powerMenu.implicitHeight
Action {
icon.name: "power"
text: Translation.tr("Shut down")
onTriggered: Session.poweroff()
}
Action {
icon.name: "arrow-counterclockwise"
text: Translation.tr("Restart")
onTriggered: Session.reboot()
}
}
}
component CancelButton: WBorderlessButton {
id: root
implicitHeight: 32
colBackground: Looks.colors.bg1Base
colBackgroundHover: Qt.lighter(Looks.colors.bg1Base, 1.2)
colBackgroundActive: Qt.lighter(Looks.colors.bg1Base, 1.1)
colBackground: Looks.darkColors.bg1Base
colBackgroundHover: Qt.lighter(Looks.darkColors.bg1Base, 1.2)
colBackgroundActive: Qt.lighter(Looks.darkColors.bg1Base, 1.1)
colForeground: Looks.darkColors.fg
property bool keyboardDown: false
@@ -172,6 +121,7 @@ Item {
text: Translation.tr("Cancel")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Looks.font.pixelSize.large
color: root.colForeground
}
Rectangle {
@@ -12,6 +12,7 @@ WTextButton {
property bool keyboardDown: false
property alias focusRingRadius: focusRing.radius
fgColor: (root.pressed || root.keyboardDown) ? Looks.darkColors.fg1 : Looks.darkColors.fg
Keys.onPressed: event => {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
@@ -34,7 +35,7 @@ WTextButton {
WText {
id: buttonText
anchors.fill: parent
color: (root.pressed || root.keyboardDown) ? Looks.colors.fg1 : Looks.colors.fg
color: root.fgColor
text: root.text
font.pixelSize: Looks.font.pixelSize.large
}