1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-07 22:15:38 -05:00

create lock screen singleton

This commit is contained in:
bbedward
2025-08-13 21:01:35 -04:00
parent c3cccda37e
commit c9be03ddaf
3 changed files with 490 additions and 382 deletions

View File

@@ -5,6 +5,7 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Services
Item { Item {
id: root id: root
@@ -54,6 +55,7 @@ Item {
onStreamFinished: { onStreamFinished: {
if (text.includes("true")) { if (text.includes("true")) {
console.log("Session is locked on startup, activating lock screen") console.log("Session is locked on startup, activating lock screen")
LockScreenService.resetState();
loader.activeAsync = true loader.activeAsync = true
} }
} }
@@ -77,12 +79,14 @@ Item {
onRead: (line) => { onRead: (line) => {
if (line.includes("org.freedesktop.login1.Session.Lock")) { if (line.includes("org.freedesktop.login1.Session.Lock")) {
console.log("login1: Lock signal received -> show lock") console.log("login1: Lock signal received -> show lock")
LockScreenService.resetState();
loader.activeAsync = true loader.activeAsync = true
} else if (line.includes("org.freedesktop.login1.Session.Unlock")) { } else if (line.includes("org.freedesktop.login1.Session.Unlock")) {
console.log("login1: Unlock signal received -> hide lock") console.log("login1: Unlock signal received -> hide lock")
loader.active = false loader.active = false
} else if (line.includes("LockedHint") && line.includes("true")) { } else if (line.includes("LockedHint") && line.includes("true")) {
console.log("login1: LockedHint=true -> show lock") console.log("login1: LockedHint=true -> show lock")
LockScreenService.resetState();
loader.activeAsync = true loader.activeAsync = true
} else if (line.includes("LockedHint") && line.includes("false")) { } else if (line.includes("LockedHint") && line.includes("false")) {
console.log("login1: LockedHint=false -> hide lock") console.log("login1: LockedHint=false -> hide lock")
@@ -135,6 +139,7 @@ Item {
function lock(): void { function lock(): void {
console.log("Lock screen requested via IPC") console.log("Lock screen requested via IPC")
LockScreenService.resetState();
loader.activeAsync = true loader.activeAsync = true
} }

View File

@@ -16,68 +16,24 @@ Item {
property string passwordBuffer: "" property string passwordBuffer: ""
property bool demoMode: false property bool demoMode: false
property bool unlocking: false
property var powerModal: null property var powerModal: null
property string confirmAction: "" property string confirmAction: ""
property var facts: [
"A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.",
"A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.",
"Right now, 100 trillion solar neutrinos are passing through your body every second.",
"The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.",
"The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.",
"There's a nebula out there that's actually colder than empty space itself.",
"We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.",
"Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.",
"Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.",
"Distant galaxies can move away from us faster than light because space itself is stretching.",
"The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.",
"The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.",
"A day on Venus lasts longer than its entire year around the Sun.",
"On Mercury, the time between sunrises is 176 Earth days long.",
"In about 4.5 billion years, our galaxy will smash into Andromeda.",
"Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.",
"PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.",
"Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.",
"Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.",
"Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.",
"Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.",
"Counting to a billion at one number per second would take over 31 years.",
"Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.",
"Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.",
"Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.",
"Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.",
"Even at light-speed, you'd never catch up to most galaxies—space expands faster.",
"Only around 5% of galaxies are ever reachable—even at light-speed.",
"If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.",
"If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.",
"Our oldest radio signals will reach the Milky Way's center in 26,000 years.",
"Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.",
"The Moon moves 3.8 centimeters farther from Earth every year.",
"The universe creates 275 million new stars every single day.",
"Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.",
"If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.",
"The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."
];
property string randomFact: ""
signal unlockRequested() signal unlockRequested
function pickRandomFact() {
randomFact = facts[Math.floor(Math.random() * facts.length)];
}
Component.onCompleted: { Component.onCompleted: {
pickRandomFact(); if (demoMode)
WeatherService.addRef(); LockScreenService.pickRandomFact()
UserInfoService.refreshUserInfo();
WeatherService.addRef()
UserInfoService.refreshUserInfo()
} }
onDemoModeChanged: { onDemoModeChanged: {
if (demoMode) if (demoMode)
pickRandomFact(); LockScreenService.pickRandomFact()
} }
Component.onDestruction: { Component.onDestruction: {
WeatherService.removeRef(); WeatherService.removeRef()
} }
Image { Image {
@@ -105,9 +61,7 @@ Item {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
Rectangle { Rectangle {
@@ -137,7 +91,11 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top anchors.top: parent.top
text: SettingsData.use24HourClock ? Qt.formatTime(systemClock.date, "H:mm") : Qt.formatTime(systemClock.date, "h:mm AP") text: SettingsData.use24HourClock ? Qt.formatTime(
systemClock.date,
"H:mm") : Qt.formatTime(
systemClock.date,
"h:mm AP")
font.pixelSize: 120 font.pixelSize: 120
font.weight: Font.Light font.weight: Font.Light
color: "white" color: "white"
@@ -148,12 +106,12 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: clockText.bottom anchors.top: clockText.bottom
anchors.topMargin: -20 anchors.topMargin: -20
text: Qt.formatDate(systemClock.date, SettingsData.lockDateFormat) text: Qt.formatDate(systemClock.date,
SettingsData.lockDateFormat)
font.pixelSize: Theme.fontSizeXLarge font.pixelSize: Theme.fontSizeXLarge
color: "white" color: "white"
opacity: 0.9 opacity: 0.9
} }
} }
ColumnLayout { ColumnLayout {
@@ -188,12 +146,12 @@ Item {
source: { source: {
if (PortalService.profileImage === "") if (PortalService.profileImage === "")
return ""; return ""
if (PortalService.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage; return "file://" + PortalService.profileImage
return PortalService.profileImage; return PortalService.profileImage
} }
smooth: true smooth: true
asynchronous: true asynchronous: true
@@ -228,7 +186,6 @@ Item {
color: "black" color: "black"
antialiasing: true antialiasing: true
} }
} }
Rectangle { Rectangle {
@@ -243,7 +200,6 @@ Item {
size: Theme.iconSize + 4 size: Theme.iconSize + 4
color: Theme.primaryText color: Theme.primaryText
} }
} }
DankIcon { DankIcon {
@@ -251,9 +207,9 @@ Item {
name: "warning" name: "warning"
size: Theme.iconSize + 4 size: Theme.iconSize + 4
color: Theme.primaryText color: Theme.primaryText
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error visible: PortalService.profileImage !== ""
&& profileImageLoader.status === Image.Error
} }
} }
Rectangle { Rectangle {
@@ -262,8 +218,11 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 60 Layout.preferredHeight: 60
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) color: Qt.rgba(Theme.surfaceContainer.r,
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.9)
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(
1, 1, 1, 0.3)
border.width: passwordField.activeFocus ? 2 : 1 border.width: passwordField.activeFocus ? 2 : 1
DankIcon { DankIcon {
@@ -289,23 +248,24 @@ Item {
echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password
onTextChanged: { onTextChanged: {
if (!demoMode) if (!demoMode)
root.passwordBuffer = text; root.passwordBuffer = text
} }
onAccepted: { onAccepted: {
if (!demoMode && root.passwordBuffer.length > 0 && !pam.active) { if (!demoMode && root.passwordBuffer.length > 0
console.log("Enter pressed, starting PAM authentication"); && !pam.active) {
pam.start(); console.log("Enter pressed, starting PAM authentication")
pam.start()
} }
} }
Keys.onPressed: (event) => { Keys.onPressed: event => {
if (demoMode) if (demoMode)
return ; return
if (pam.active) { if (pam.active) {
console.log("PAM is active, ignoring input"); console.log(
event.accepted = true; "PAM is active, ignoring input")
return ; event.accepted = true
return
} }
} }
@@ -316,7 +276,6 @@ Item {
running: !demoMode running: !demoMode
onTriggered: passwordField.forceActiveFocus() onTriggered: passwordField.forceActiveFocus()
} }
} }
StyledText { StyledText {
@@ -331,26 +290,26 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: { text: {
if (demoMode) if (demoMode)
return ""; return ""
if (root.unlocking) if (LockScreenService.unlocking)
return "Unlocking..."; return "Unlocking..."
if (pam.active) if (pam.active)
return "Authenticating..."; return "Authenticating..."
return "hunter2"; return "Password..."
} }
color: root.unlocking ? Theme.primary : (pam.active ? Theme.primary : Theme.outline) color: LockScreenService.unlocking ? Theme.primary : (pam.active ? Theme.primary : Theme.outline)
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0 opacity: (demoMode
|| root.passwordBuffer.length === 0) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on color { Behavior on color {
@@ -358,9 +317,7 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
StyledText { StyledText {
@@ -371,15 +328,18 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: { text: {
if (demoMode) if (demoMode)
return "••••••••"; return "••••••••"
else if (parent.showPassword) else if (parent.showPassword)
return root.passwordBuffer; return root.passwordBuffer
else else
return "•".repeat(Math.min(root.passwordBuffer.length, 25)); return "•".repeat(
Math.min(
root.passwordBuffer.length, 25))
} }
color: Theme.surfaceText color: Theme.surfaceText
font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge
opacity: (demoMode || root.passwordBuffer.length > 0) ? 1 : 0 opacity: (demoMode
|| root.passwordBuffer.length > 0) ? 1 : 0
elide: Text.ElideRight elide: Text.ElideRight
Behavior on opacity { Behavior on opacity {
@@ -387,9 +347,7 @@ Item {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
DankActionButton { DankActionButton {
@@ -400,7 +358,8 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
iconName: parent.showPassword ? "visibility_off" : "visibility" iconName: parent.showPassword ? "visibility_off" : "visibility"
buttonSize: 32 buttonSize: 32
visible: !demoMode && root.passwordBuffer.length > 0 && !pam.active && !root.unlocking visible: !demoMode && root.passwordBuffer.length > 0
&& !pam.active && !LockScreenService.unlocking
enabled: visible enabled: visible
onClicked: parent.showPassword = !parent.showPassword onClicked: parent.showPassword = !parent.showPassword
} }
@@ -415,17 +374,18 @@ Item {
height: 24 height: 24
radius: 12 radius: 12
color: "transparent" color: "transparent"
visible: !demoMode && (pam.active || root.unlocking) visible: !demoMode && (pam.active
|| LockScreenService.unlocking)
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: "check_circle" name: "check_circle"
size: 20 size: 20
color: Theme.primary color: Theme.primary
visible: root.unlocking visible: LockScreenService.unlocking
SequentialAnimation on scale { SequentialAnimation on scale {
running: root.unlocking running: LockScreenService.unlocking
NumberAnimation { NumberAnimation {
from: 0 from: 0
@@ -442,14 +402,12 @@ Item {
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasizedAccel easing.bezierCurve: Anims.emphasizedAccel
} }
} }
} }
Item { Item {
anchors.fill: parent anchors.fill: parent
visible: pam.active && !root.unlocking visible: pam.active && !LockScreenService.unlocking
Rectangle { Rectangle {
width: 20 width: 20
@@ -457,7 +415,9 @@ Item {
radius: 10 radius: 10
anchors.centerIn: parent anchors.centerIn: parent
color: "transparent" color: "transparent"
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) border.color: Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.3)
border.width: 2 border.width: 2
} }
@@ -475,21 +435,22 @@ Item {
height: parent.height / 2 height: parent.height / 2
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
0.9)
} }
RotationAnimation on rotation { RotationAnimation on rotation {
running: pam.active && !root.unlocking running: pam.active
&& !LockScreenService.unlocking
loops: Animation.Infinite loops: Animation.Infinite
duration: Anims.durLong duration: Anims.durLong
from: 0 from: 0
to: 360 to: 360
} }
} }
} }
} }
DankActionButton { DankActionButton {
@@ -500,12 +461,14 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
iconName: "keyboard_return" iconName: "keyboard_return"
buttonSize: 36 buttonSize: 36
visible: (demoMode || (root.passwordBuffer.length > 0 && !pam.active && !root.unlocking)) visible: (demoMode || (root.passwordBuffer.length > 0
&& !pam.active
&& !LockScreenService.unlocking))
enabled: !demoMode enabled: !demoMode
onClicked: { onClicked: {
if (!demoMode) { if (!demoMode) {
console.log("Enter button clicked, starting PAM authentication"); console.log("Enter button clicked, starting PAM authentication")
pam.start(); pam.start()
} }
} }
@@ -514,9 +477,7 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
Behavior on border.color { Behavior on border.color {
@@ -524,40 +485,36 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
} }
StyledText { StyledText {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: placeholder.pamState ? 20 : 0 Layout.preferredHeight: LockScreenService.pamState ? 20 : 0
text: { text: {
if (placeholder.pamState === "error") if (LockScreenService.pamState === "error")
return "Authentication error - try again"; return "Authentication error - try again"
if (placeholder.pamState === "max") if (LockScreenService.pamState === "max")
return "Too many attempts - locked out"; return "Too many attempts - locked out"
if (placeholder.pamState === "fail") if (LockScreenService.pamState === "fail")
return "Incorrect password - try again"; return "Incorrect password - try again"
return ""; return ""
} }
color: Theme.error color: Theme.error
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
visible: placeholder.pamState !== "" visible: LockScreenService.pamState !== ""
opacity: placeholder.pamState !== "" ? 1 : 0 opacity: LockScreenService.pamState !== "" ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on Layout.preferredHeight { Behavior on Layout.preferredHeight {
@@ -565,11 +522,8 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
} }
StyledText { StyledText {
@@ -597,7 +551,8 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
DankIcon { DankIcon {
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) name: WeatherService.getWeatherIcon(
WeatherService.weather.wCode)
size: Theme.iconSize size: Theme.iconSize
color: "white" color: "white"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -618,21 +573,28 @@ Item {
height: 24 height: 24
color: Qt.rgba(255, 255, 255, 0.2) color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) visible: WeatherService.weather.available
&& (NetworkService.networkStatus !== "disconnected"
|| BluetoothService.enabled
|| (AudioService.sink && AudioService.sink.audio)
|| BatteryService.batteryAvailable)
} }
// System status icons // System status icons
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) visible: NetworkService.networkStatus !== "disconnected"
|| (BluetoothService.available
&& BluetoothService.enabled)
|| (AudioService.sink && AudioService.sink.audio)
// Network icon // Network icon
DankIcon { DankIcon {
name: { name: {
if (NetworkService.networkStatus === "ethernet") if (NetworkService.networkStatus === "ethernet") {
return "lan" return "lan"
else if (NetworkService.networkStatus === "wifi") { } else if (NetworkService.networkStatus === "wifi") {
switch (NetworkService.wifiSignalStrengthStr) { switch (NetworkService.wifiSignalStrengthStr) {
case "excellent": case "excellent":
return "wifi" return "wifi"
@@ -645,12 +607,14 @@ Item {
default: default:
return "wifi" return "wifi"
} }
} } else {
else
return "wifi_off" return "wifi_off"
} }
}
size: Theme.iconSize - 2 size: Theme.iconSize - 2
color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) color: NetworkService.networkStatus
!== "disconnected" ? "white" : Qt.rgba(255,
255, 255, 0.5)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.networkStatus !== "disconnected" visible: NetworkService.networkStatus !== "disconnected"
} }
@@ -661,14 +625,16 @@ Item {
size: Theme.iconSize - 2 size: Theme.iconSize - 2
color: "white" color: "white"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: BluetoothService.available && BluetoothService.enabled visible: BluetoothService.available
&& BluetoothService.enabled
} }
// Volume icon // Volume icon
DankIcon { DankIcon {
name: { name: {
if (AudioService.sink && AudioService.sink.audio) { if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) if (AudioService.sink.audio.muted
|| AudioService.sink.audio.volume === 0)
return "volume_off" return "volume_off"
else if (AudioService.sink.audio.volume * 100 < 33) else if (AudioService.sink.audio.volume * 100 < 33)
return "volume_down" return "volume_down"
@@ -678,7 +644,10 @@ Item {
return "volume_up" return "volume_up"
} }
size: Theme.iconSize - 2 size: Theme.iconSize - 2
color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" color: (AudioService.sink && AudioService.sink.audio
&& (AudioService.sink.audio.muted
|| AudioService.sink.audio.volume
=== 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: AudioService.sink && AudioService.sink.audio visible: AudioService.sink && AudioService.sink.audio
} }
@@ -690,7 +659,10 @@ Item {
height: 24 height: 24
color: Qt.rgba(255, 255, 255, 0.2) color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) visible: BatteryService.batteryAvailable
&& (NetworkService.networkStatus !== "disconnected"
|| BluetoothService.enabled
|| (AudioService.sink && AudioService.sink.audio))
} }
// Battery section // Battery section
@@ -704,57 +676,77 @@ Item {
if (BatteryService.isCharging) { if (BatteryService.isCharging) {
if (BatteryService.batteryLevel >= 90) if (BatteryService.batteryLevel >= 90)
return "battery_charging_full" return "battery_charging_full"
if (BatteryService.batteryLevel >= 80) if (BatteryService.batteryLevel >= 80)
return "battery_charging_90" return "battery_charging_90"
if (BatteryService.batteryLevel >= 60) if (BatteryService.batteryLevel >= 60)
return "battery_charging_80" return "battery_charging_80"
if (BatteryService.batteryLevel >= 50) if (BatteryService.batteryLevel >= 50)
return "battery_charging_60" return "battery_charging_60"
if (BatteryService.batteryLevel >= 30) if (BatteryService.batteryLevel >= 30)
return "battery_charging_50" return "battery_charging_50"
if (BatteryService.batteryLevel >= 20) if (BatteryService.batteryLevel >= 20)
return "battery_charging_30" return "battery_charging_30"
return "battery_charging_20" return "battery_charging_20"
} }
// Check if plugged in but not charging (like at 80% charge limit) // Check if plugged in but not charging (like at 80% charge limit)
if (BatteryService.isPluggedIn) { if (BatteryService.isPluggedIn) {
if (BatteryService.batteryLevel >= 90) if (BatteryService.batteryLevel >= 90)
return "battery_charging_full" return "battery_charging_full"
if (BatteryService.batteryLevel >= 80) if (BatteryService.batteryLevel >= 80)
return "battery_charging_90" return "battery_charging_90"
if (BatteryService.batteryLevel >= 60) if (BatteryService.batteryLevel >= 60)
return "battery_charging_80" return "battery_charging_80"
if (BatteryService.batteryLevel >= 50) if (BatteryService.batteryLevel >= 50)
return "battery_charging_60" return "battery_charging_60"
if (BatteryService.batteryLevel >= 30) if (BatteryService.batteryLevel >= 30)
return "battery_charging_50" return "battery_charging_50"
if (BatteryService.batteryLevel >= 20) if (BatteryService.batteryLevel >= 20)
return "battery_charging_30" return "battery_charging_30"
return "battery_charging_20" return "battery_charging_20"
} }
// On battery power // On battery power
if (BatteryService.batteryLevel >= 95) if (BatteryService.batteryLevel >= 95)
return "battery_full" return "battery_full"
if (BatteryService.batteryLevel >= 85) if (BatteryService.batteryLevel >= 85)
return "battery_6_bar" return "battery_6_bar"
if (BatteryService.batteryLevel >= 70) if (BatteryService.batteryLevel >= 70)
return "battery_5_bar" return "battery_5_bar"
if (BatteryService.batteryLevel >= 55) if (BatteryService.batteryLevel >= 55)
return "battery_4_bar" return "battery_4_bar"
if (BatteryService.batteryLevel >= 40) if (BatteryService.batteryLevel >= 40)
return "battery_3_bar" return "battery_3_bar"
if (BatteryService.batteryLevel >= 25) if (BatteryService.batteryLevel >= 25)
return "battery_2_bar" return "battery_2_bar"
return "battery_1_bar" return "battery_1_bar"
} }
size: Theme.iconSize size: Theme.iconSize
color: { color: {
if (BatteryService.isLowBattery && !BatteryService.isCharging) if (BatteryService.isLowBattery
&& !BatteryService.isCharging)
return Theme.error return Theme.error
if (BatteryService.isCharging || BatteryService.isPluggedIn)
if (BatteryService.isCharging
|| BatteryService.isPluggedIn)
return Theme.primary return Theme.primary
return "white" return "white"
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -782,9 +774,9 @@ Item {
buttonSize: 40 buttonSize: 40
onClicked: { onClicked: {
if (demoMode) if (demoMode)
console.log("Demo: Power"); console.log("Demo: Power")
else else
powerDialog.open(); LockScreenService.showPowerDialog()
} }
} }
@@ -793,9 +785,9 @@ Item {
buttonSize: 40 buttonSize: 40
onClicked: { onClicked: {
if (demoMode) if (demoMode)
console.log("Demo: Reboot"); console.log("Demo: Reboot")
else else
rebootDialog.open(); LockScreenService.showRebootDialog()
} }
} }
@@ -804,12 +796,11 @@ Item {
buttonSize: 40 buttonSize: 40
onClicked: { onClicked: {
if (demoMode) if (demoMode)
console.log("Demo: Logout"); console.log("Demo: Logout")
else else
logoutDialog.open(); LockScreenService.showLogoutDialog()
} }
} }
} }
StyledText { StyledText {
@@ -817,15 +808,14 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
width: Math.min(parent.width - Theme.spacingXL * 2, implicitWidth) width: Math.min(parent.width - Theme.spacingXL * 2, implicitWidth)
text: randomFact text: LockScreenService.randomFact
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: "white" color: "white"
opacity: 0.8 opacity: 0.8
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
visible: randomFact !== "" visible: LockScreenService.randomFact !== ""
} }
} }
FileView { FileView {
@@ -841,36 +831,38 @@ Item {
config: pamConfigWatcher.loaded ? "dankshell" : "login" config: pamConfigWatcher.loaded ? "dankshell" : "login"
onResponseRequiredChanged: { onResponseRequiredChanged: {
if (demoMode) if (demoMode)
return ; return
console.log("PAM response required:", responseRequired); console.log("PAM response required:", responseRequired)
if (!responseRequired) if (!responseRequired)
return ; return
console.log("Responding to PAM with password buffer length:", root.passwordBuffer.length); console.log("Responding to PAM with password buffer length:",
respond(root.passwordBuffer); root.passwordBuffer.length)
respond(root.passwordBuffer)
} }
onCompleted: (res) => { onCompleted: res => {
if (demoMode) if (demoMode)
return ; return
console.log("PAM authentication completed with result:", res); console.log(
"PAM authentication completed with result:", res)
if (res === PamResult.Success) { if (res === PamResult.Success) {
console.log("Authentication successful, unlocking"); console.log("Authentication successful, unlocking")
root.unlocking = true; LockScreenService.setUnlocking(true)
passwordField.text = ""; passwordField.text = ""
root.passwordBuffer = ""; root.passwordBuffer = ""
root.unlockRequested(); root.unlockRequested()
return ; return
} }
console.log("Authentication failed:", res); console.log("Authentication failed:", res)
if (res === PamResult.Error) if (res === PamResult.Error)
placeholder.pamState = "error"; LockScreenService.setPamState("error")
else if (res === PamResult.MaxTries) else if (res === PamResult.MaxTries)
placeholder.pamState = "max"; LockScreenService.setPamState("max")
else if (res === PamResult.Failed) else if (res === PamResult.Failed)
placeholder.pamState = "fail"; LockScreenService.setPamState("fail")
placeholderDelay.restart(); placeholderDelay.restart()
} }
} }
@@ -878,7 +870,7 @@ Item {
id: placeholderDelay id: placeholderDelay
interval: 4000 interval: 4000
onTriggered: placeholder.pamState = "" onTriggered: LockScreenService.setPamState("")
} }
MouseArea { MouseArea {
@@ -891,16 +883,16 @@ Item {
id: powerDialog id: powerDialog
function open() { function open() {
visible = true; LockScreenService.showPowerDialog()
} }
function close() { function close() {
visible = false; LockScreenService.hidePowerDialog()
} }
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8) color: Qt.rgba(0, 0, 0, 0.8)
visible: false visible: LockScreenService.powerDialogVisible
z: 1000 z: 1000
Rectangle { Rectangle {
@@ -939,7 +931,11 @@ Item {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: cancelMouse1.pressed ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.7) : cancelMouse1.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant color: cancelMouse1.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse1.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -956,14 +952,17 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: powerDialog.close() onClicked: powerDialog.close()
} }
} }
Rectangle { Rectangle {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: powerMouse.pressed ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8) : powerMouse.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 1) : Theme.error color: powerMouse.pressed ? Qt.rgba(
Theme.error.r,
Theme.error.g,
Theme.error.b,
0.8) : powerMouse.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 1) : Theme.error
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -980,35 +979,31 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
powerDialog.close(); powerDialog.close()
Quickshell.execDetached(["systemctl", "poweroff"]); Quickshell.execDetached(
["systemctl", "poweroff"])
} }
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
id: rebootDialog id: rebootDialog
function open() { function open() {
visible = true; LockScreenService.showRebootDialog()
} }
function close() { function close() {
visible = false; LockScreenService.hideRebootDialog()
} }
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8) color: Qt.rgba(0, 0, 0, 0.8)
visible: false visible: LockScreenService.rebootDialogVisible
z: 1000 z: 1000
Rectangle { Rectangle {
@@ -1047,7 +1042,11 @@ Item {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: cancelMouse2.pressed ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.7) : cancelMouse2.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant color: cancelMouse2.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse2.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -1064,14 +1063,17 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: rebootDialog.close() onClicked: rebootDialog.close()
} }
} }
Rectangle { Rectangle {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: rebootMouse.pressed ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.8) : rebootMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary color: rebootMouse.pressed ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.8) : rebootMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -1088,35 +1090,30 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
rebootDialog.close(); rebootDialog.close()
Quickshell.execDetached(["systemctl", "reboot"]); Quickshell.execDetached(["systemctl", "reboot"])
} }
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
id: logoutDialog id: logoutDialog
function open() { function open() {
visible = true; LockScreenService.showLogoutDialog()
} }
function close() { function close() {
visible = false; LockScreenService.hideLogoutDialog()
} }
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8) color: Qt.rgba(0, 0, 0, 0.8)
visible: false visible: LockScreenService.logoutDialogVisible
z: 1000 z: 1000
Rectangle { Rectangle {
@@ -1155,7 +1152,11 @@ Item {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: cancelMouse3.pressed ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.7) : cancelMouse3.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant color: cancelMouse3.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse3.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -1172,14 +1173,17 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: logoutDialog.close() onClicked: logoutDialog.close()
} }
} }
Rectangle { Rectangle {
width: 100 width: 100
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: logoutMouse.pressed ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.8) : logoutMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary color: logoutMouse.pressed ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.8) : logoutMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
@@ -1196,19 +1200,13 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
logoutDialog.close(); logoutDialog.close()
NiriService.quit(); NiriService.quit()
} }
} }
} }
} }
} }
} }
} }
} }

View File

@@ -0,0 +1,105 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
id: root
property bool unlocking: false
property string randomFact: ""
property string pamState: ""
property bool powerDialogVisible: false
property bool rebootDialogVisible: false
property bool logoutDialogVisible: false
property var facts: [
"A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.",
"A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.",
"Right now, 100 trillion solar neutrinos are passing through your body every second.",
"The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.",
"The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.",
"There's a nebula out there that's actually colder than empty space itself.",
"We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.",
"Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.",
"Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.",
"Distant galaxies can move away from us faster than light because space itself is stretching.",
"The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.",
"The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.",
"A day on Venus lasts longer than its entire year around the Sun.",
"On Mercury, the time between sunrises is 176 Earth days long.",
"In about 4.5 billion years, our galaxy will smash into Andromeda.",
"Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.",
"PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.",
"Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.",
"Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.",
"Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.",
"Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.",
"Counting to a billion at one number per second would take over 31 years.",
"Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.",
"Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.",
"Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.",
"Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.",
"Even at light-speed, you'd never catch up to most galaxies—space expands faster.",
"Only around 5% of galaxies are ever reachable—even at light-speed.",
"If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.",
"If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.",
"Our oldest radio signals will reach the Milky Way's center in 26,000 years.",
"Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.",
"The Moon moves 3.8 centimeters farther from Earth every year.",
"The universe creates 275 million new stars every single day.",
"Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.",
"If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.",
"The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."
]
function pickRandomFact() {
randomFact = facts[Math.floor(Math.random() * facts.length)];
}
function resetState() {
unlocking = false;
pamState = "";
powerDialogVisible = false;
rebootDialogVisible = false;
logoutDialogVisible = false;
pickRandomFact();
}
function setPamState(state) {
pamState = state;
}
function setUnlocking(value) {
unlocking = value;
}
function showPowerDialog() {
powerDialogVisible = true;
}
function hidePowerDialog() {
powerDialogVisible = false;
}
function showRebootDialog() {
rebootDialogVisible = true;
}
function hideRebootDialog() {
rebootDialogVisible = false;
}
function showLogoutDialog() {
logoutDialogVisible = true;
}
function hideLogoutDialog() {
logoutDialogVisible = false;
}
Component.onCompleted: {
pickRandomFact();
}
}