diff --git a/default/sddm/blob/Main.qml b/default/sddm/blob/Main.qml index bb4e04e..273f5cf 100644 --- a/default/sddm/blob/Main.qml +++ b/default/sddm/blob/Main.qml @@ -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() } + 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 { - anchors.centerIn: parent - spacing: 48 + id: clockColumn + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: inputField.top + anchors.bottomMargin: root.sectionGap - Column { + Text { 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 - } + text: Qt.formatTime(clock.now, "HH:mm") + color: root.textColor + font.family: root.fontFamily + font.pixelSize: root.clockFontSize } - Rectangle { + Text { 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 - } - } + text: Qt.formatDate(clock.now, "dddd, d MMMM") + color: root.placeholderColor + font.family: root.fontFamily + font.pixelSize: root.dateFontSize } } Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 64 - color: root.panelColor + id: inputField + anchors.centerIn: parent + 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 - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: 1 - color: root.faintTextColor + 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: 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 = "" } - FooterButton { - anchors.left: parent.left - anchors.leftMargin: 32 - anchors.verticalCenter: parent.verticalCenter - text: "SESSION " + root.sessionName(root.sessionIndex).toUpperCase() + Text { + 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: root.fieldFontSize + font.italic: root.errorState + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + + Text { + 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: root.smallFontSize + + MouseArea { + id: userArea + anchors.fill: parent + anchors.margins: -8 + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: root.changeUser() + } + } + + Text { + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: root.edgeMargin + text: root.sessionName(root.sessionIndex) + color: sessionArea.containsMouse ? root.textColor : root.placeholderColor + font.family: root.fontFamily + font.pixelSize: root.smallFontSize + + 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 + Row { + anchors.right: parent.right + 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" } + ] - FooterButton { - visible: sddm.canPowerOff - text: "SHUT DOWN" - onClicked: sddm.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() + } } } } - Component.onCompleted: { - if (usernameField.text.length > 0) passwordField.input.forceActiveFocus() - else usernameField.input.forceActiveFocus() - } + Component.onCompleted: fieldInput.forceActiveFocus() }