Match the login screen to the lock screen

This commit is contained in:
SirBlob committed 2026-09-27 01:16:20 +00:00
1 parent 8da99c25e9
commit 6a49d5e0cb
1 file changed
+173 -214
+173 -214
View File
@@ -8,96 +8,38 @@ Rectangle {
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)
readonly property color placeholderColor: Qt.rgba(textColor.r, textColor.g, textColor.b, 0.66)
readonly property color restingBorderColor: Qt.rgba(textColor.r, textColor.g, textColor.b, 0.5)
readonly property color fieldBackgroundColor: Qt.darker(backgroundColor, 1.25)
readonly property int fieldWidth: 381
readonly property int fieldHeight: 67
readonly property int outlineThickness: 2
readonly property int fieldFontSize: 18
readonly property int passwordDotFontSize: 21
readonly property int passwordDotLetterSpacing: 3
readonly property int clockFontSize: 72
readonly property int dateFontSize: 18
readonly property int smallFontSize: 14
readonly property int sectionGap: 48
readonly property int edgeMargin: 32
property string username: userModel.lastUser
property bool enteringUsername: username.length === 0
property int sessionIndex: sessionModel.lastIndex >= 0 ? sessionModel.lastIndex : 0
property string statusMessage: ""
property bool loggingIn: false
property string failureMessage: ""
property bool authenticating: false
readonly property bool errorState: failureMessage.length > 0
readonly property bool inputActive: fieldInput.text.length > 0 || authenticating
readonly property string placeholderText: authenticating ? "Checking..."
: errorState ? failureMessage
: enteringUsername ? "Enter Username"
: "Enter Password"
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()
}
}
color: backgroundColor
function sessionName(index) {
var session = sessionNames.itemAt(index)
@@ -108,15 +50,28 @@ Rectangle {
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()
function changeUser() {
root.failureMessage = ""
root.enteringUsername = true
fieldInput.text = root.username
fieldInput.forceActiveFocus()
}
function submit() {
var entered = fieldInput.text
if (root.authenticating || entered.length === 0) return
if (root.enteringUsername) {
root.username = entered
root.enteringUsername = false
fieldInput.text = ""
return
}
root.loggingIn = true
root.statusMessage = ""
sddm.login(usernameField.text, passwordField.text, root.sessionIndex)
fieldInput.text = ""
root.failureMessage = ""
root.authenticating = true
sddm.login(root.username, entered, root.sessionIndex)
}
Repeater {
@@ -133,14 +88,9 @@ Rectangle {
target: sddm
function onLoginFailed() {
root.loggingIn = false
root.statusMessage = "Wrong password, try again"
passwordField.text = ""
passwordField.input.forceActiveFocus()
}
function onLoginSucceeded() {
root.statusMessage = ""
root.authenticating = false
root.failureMessage = "Wrong password"
fieldInput.forceActiveFocus()
}
}
@@ -156,166 +106,175 @@ Rectangle {
onTriggered: clock.now = new Date()
}
Column {
anchors.centerIn: parent
spacing: 48
MouseArea {
anchors.fill: parent
onClicked: fieldInput.forceActiveFocus()
}
Image {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: clockColumn.top
anchors.bottomMargin: root.sectionGap
width: 96
height: 96
source: "logo.png"
sourceSize.width: 192
sourceSize.height: 192
fillMode: Image.PreserveAspectFit
onStatusChanged: if (status === Image.Error && source.toString().endsWith("logo.png")) source = "logo.svg"
}
Column {
id: clockColumn
anchors.horizontalCenter: parent.horizontalCenter
spacing: 4
anchors.bottom: inputField.top
anchors.bottomMargin: root.sectionGap
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
font.pixelSize: root.clockFontSize
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatDate(clock.now, "dddd, MMMM d").toUpperCase()
color: root.mutedTextColor
text: Qt.formatDate(clock.now, "dddd, d MMMM")
color: root.placeholderColor
font.family: root.fontFamily
font.pixelSize: 14
font.letterSpacing: 4
font.pixelSize: root.dateFontSize
}
}
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
id: inputField
anchors.centerIn: parent
spacing: 28
width: root.fieldWidth
height: root.fieldHeight
color: root.fieldBackgroundColor
border.width: root.outlineThickness
border.color: root.errorState ? root.errorColor
: root.inputActive ? root.textColor
: root.restingBorderColor
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"
TextInput {
id: fieldInput
anchors.fill: parent
anchors.margins: root.outlineThickness
anchors.leftMargin: 18
anchors.rightMargin: 18
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignHCenter
clip: true
focus: true
readOnly: root.authenticating
echoMode: root.enteringUsername ? TextInput.Normal : TextInput.Password
passwordCharacter: "●"
passwordMaskDelay: 0
color: root.textColor
selectionColor: root.restingBorderColor
font.family: root.fontFamily
font.pixelSize: 18
font.pixelSize: text.length > 0 && !root.enteringUsername ? root.passwordDotFontSize : root.fieldFontSize
font.letterSpacing: text.length > 0 && !root.enteringUsername ? root.passwordDotLetterSpacing : 0
cursorDelegate: Rectangle {
width: 2
color: root.textColor
visible: fieldInput.cursorVisible && fieldInput.text.length > 0
}
onTextChanged: if (text.length > 0) root.failureMessage = ""
onAccepted: root.submit()
Keys.onEscapePressed: text = ""
}
Text {
text: "Sign in to continue"
color: root.mutedTextColor
anchors.fill: fieldInput
visible: fieldInput.text.length === 0
text: root.placeholderText
color: root.authenticating ? root.textColor
: root.errorState ? root.errorColor
: root.placeholderColor
font.family: root.fontFamily
font.pixelSize: 12
font.pixelSize: root.fieldFontSize
font.italic: root.errorState
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
}
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
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: inputField.bottom
anchors.topMargin: 20
visible: !root.enteringUsername
text: root.username
color: userArea.containsMouse ? root.textColor : root.placeholderColor
font.family: root.fontFamily
font.pixelSize: 12
}
}
font.pixelSize: root.smallFontSize
MouseArea {
id: userArea
anchors.fill: parent
anchors.margins: -8
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.changeUser()
}
}
Rectangle {
Text {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 64
color: root.panelColor
anchors.margins: root.edgeMargin
text: root.sessionName(root.sessionIndex)
color: sessionArea.containsMouse ? root.textColor : root.placeholderColor
font.family: root.fontFamily
font.pixelSize: root.smallFontSize
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()
MouseArea {
id: sessionArea
anchors.fill: parent
anchors.margins: -8
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.nextSession()
}
}
Row {
anchors.right: parent.right
anchors.rightMargin: 32
anchors.verticalCenter: parent.verticalCenter
spacing: 32
anchors.bottom: parent.bottom
anchors.margins: root.edgeMargin
spacing: 28
FooterButton {
visible: sddm.canReboot
text: "REBOOT"
onClicked: sddm.reboot()
Repeater {
model: [
{ label: "Reboot", available: sddm.canReboot, action: "reboot" },
{ label: "Shut Down", available: sddm.canPowerOff, action: "powerOff" }
]
Text {
required property var modelData
visible: modelData.available
text: modelData.label
color: powerArea.containsMouse ? root.textColor : root.placeholderColor
font.family: root.fontFamily
font.pixelSize: root.smallFontSize
MouseArea {
id: powerArea
anchors.fill: parent
anchors.margins: -8
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: modelData.action === "reboot" ? sddm.reboot() : sddm.powerOff()
}
FooterButton {
visible: sddm.canPowerOff
text: "SHUT DOWN"
onClicked: sddm.powerOff()
}
}
}
Component.onCompleted: {
if (usernameField.text.length > 0) passwordField.input.forceActiveFocus()
else usernameField.input.forceActiveFocus()
}
Component.onCompleted: fieldInput.forceActiveFocus()
}