Files
dotfiles/default/sddm/blob/Main.qml
T
2026-09-27 00:53:03 +00:00

322 lines
8.1 KiB
QML

import QtQuick
Rectangle {
id: root
readonly property color backgroundColor: "#1a1b26"
readonly property color textColor: "#ffffff"
readonly property color errorColor: "#f7768e"
readonly property string fontFamily: "monospace"
readonly property color mutedTextColor: Qt.rgba(textColor.r, textColor.g, textColor.b, 0.55)
readonly property color faintTextColor: Qt.rgba(textColor.r, textColor.g, textColor.b, 0.18)
readonly property color panelColor: Qt.rgba(textColor.r, textColor.g, textColor.b, 0.04)
property int sessionIndex: sessionModel.lastIndex >= 0 ? sessionModel.lastIndex : 0
property string statusMessage: ""
property bool loggingIn: false
width: 1920
height: 1080
gradient: Gradient {
GradientStop { position: 0.0; color: root.backgroundColor }
GradientStop { position: 1.0; color: Qt.darker(root.backgroundColor, 1.35) }
}
component LoginField: Item {
id: field
property string label: ""
property bool hasError: false
property bool isPassword: false
property Item nextField: null
property Item previousField: null
property alias input: fieldInput
property alias text: fieldInput.text
signal submitted()
width: 320
height: 58
Text {
id: fieldLabel
text: field.label.toUpperCase()
color: fieldInput.activeFocus ? root.textColor : root.mutedTextColor
font.family: root.fontFamily
font.pixelSize: 11
font.letterSpacing: 2
}
TextInput {
id: fieldInput
anchors.left: parent.left
anchors.right: parent.right
anchors.top: fieldLabel.bottom
anchors.topMargin: 10
color: root.textColor
selectionColor: root.faintTextColor
echoMode: field.isPassword ? TextInput.Password : TextInput.Normal
passwordCharacter: "•"
font.family: root.fontFamily
font.pixelSize: 18
clip: true
KeyNavigation.tab: field.nextField ? field.nextField.input : null
KeyNavigation.backtab: field.previousField ? field.previousField.input : null
Keys.onReturnPressed: field.submitted()
Keys.onEnterPressed: field.submitted()
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: fieldInput.activeFocus || field.hasError ? 2 : 1
color: field.hasError ? root.errorColor
: fieldInput.activeFocus ? root.textColor
: root.faintTextColor
}
}
component FooterButton: Text {
id: footerButton
signal clicked()
color: footerArea.containsMouse ? root.textColor : root.mutedTextColor
font.family: root.fontFamily
font.pixelSize: 12
font.letterSpacing: 2
MouseArea {
id: footerArea
anchors.fill: parent
anchors.margins: -8
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: footerButton.clicked()
}
}
function sessionName(index) {
var session = sessionNames.itemAt(index)
return session ? session.sessionName : ""
}
function nextSession() {
if (sessionNames.count > 0) root.sessionIndex = (root.sessionIndex + 1) % sessionNames.count
}
function login() {
if (root.loggingIn) return
if (usernameField.text.length === 0) {
usernameField.input.forceActiveFocus()
return
}
root.loggingIn = true
root.statusMessage = ""
sddm.login(usernameField.text, passwordField.text, root.sessionIndex)
}
Repeater {
id: sessionNames
model: sessionModel
Item {
required property string name
readonly property string sessionName: name
}
}
Connections {
target: sddm
function onLoginFailed() {
root.loggingIn = false
root.statusMessage = "Wrong password, try again"
passwordField.text = ""
passwordField.input.forceActiveFocus()
}
function onLoginSucceeded() {
root.statusMessage = ""
}
}
QtObject {
id: clock
property date now: new Date()
}
Timer {
interval: 1000
running: true
repeat: true
onTriggered: clock.now = new Date()
}
Column {
anchors.centerIn: parent
spacing: 48
Column {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 4
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatTime(clock.now, "HH:mm")
color: root.textColor
font.family: root.fontFamily
font.pixelSize: 104
font.weight: Font.Light
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatDate(clock.now, "dddd, MMMM d").toUpperCase()
color: root.mutedTextColor
font.family: root.fontFamily
font.pixelSize: 14
font.letterSpacing: 4
}
}
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
width: 400
height: loginColumn.implicitHeight + 80
color: root.panelColor
border.width: 1
border.color: root.faintTextColor
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 2
color: root.statusMessage.length > 0 ? root.errorColor : root.textColor
}
Column {
id: loginColumn
anchors.centerIn: parent
spacing: 28
Row {
spacing: 16
Image {
id: logo
width: 40
height: 40
source: "logo.png"
sourceSize.width: 80
sourceSize.height: 80
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: if (status === Image.Error && source.toString().endsWith("logo.png")) source = "logo.svg"
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Text {
text: "Welcome back"
color: root.textColor
font.family: root.fontFamily
font.pixelSize: 18
}
Text {
text: "Sign in to continue"
color: root.mutedTextColor
font.family: root.fontFamily
font.pixelSize: 12
}
}
}
LoginField {
id: usernameField
label: "Username"
text: userModel.lastUser
nextField: passwordField
onSubmitted: passwordField.input.forceActiveFocus()
}
LoginField {
id: passwordField
label: "Password"
hasError: root.statusMessage.length > 0
isPassword: true
previousField: usernameField
onSubmitted: root.login()
}
Text {
width: 320
height: 16
text: root.statusMessage.length > 0 ? root.statusMessage
: root.loggingIn ? "Signing in..."
: keyboard.capsLock ? "Caps Lock is on"
: "Press Enter to sign in"
color: root.statusMessage.length > 0 ? root.errorColor : root.mutedTextColor
font.family: root.fontFamily
font.pixelSize: 12
}
}
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 64
color: root.panelColor
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: root.faintTextColor
}
FooterButton {
anchors.left: parent.left
anchors.leftMargin: 32
anchors.verticalCenter: parent.verticalCenter
text: "SESSION " + root.sessionName(root.sessionIndex).toUpperCase()
onClicked: root.nextSession()
}
Row {
anchors.right: parent.right
anchors.rightMargin: 32
anchors.verticalCenter: parent.verticalCenter
spacing: 32
FooterButton {
visible: sddm.canReboot
text: "REBOOT"
onClicked: sddm.reboot()
}
FooterButton {
visible: sddm.canPowerOff
text: "SHUT DOWN"
onClicked: sddm.powerOff()
}
}
}
Component.onCompleted: {
if (usernameField.text.length > 0) passwordField.input.forceActiveFocus()
else usernameField.input.forceActiveFocus()
}
}