refactor(lockscreen): remove submit arrow for centered password input and enlarge session controls inside input card
This commit is contained in:
parent
aed2c0f11d
commit
b50ef1c8cb
@ -205,12 +205,12 @@ Item {
|
|||||||
|
|
||||||
Item { Layout.preferredHeight: 4 }
|
Item { Layout.preferredHeight: 4 }
|
||||||
|
|
||||||
// 3. Elegant Glass Input Card with Animated Typing Dots
|
// 3. Elegant Glass Input Card with Animated Typing Dots & Session Controls
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: cardContainer
|
id: cardContainer
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: cardLayout.implicitHeight + 36
|
implicitHeight: cardLayout.implicitHeight + 36
|
||||||
radius: 20
|
radius: 24
|
||||||
color: Theme.isDark ? Qt.rgba(30/255, 30/255, 46/255, 0.65) : Qt.rgba(240/255, 240/255, 245/255, 0.75)
|
color: Theme.isDark ? Qt.rgba(30/255, 30/255, 46/255, 0.65) : Qt.rgba(240/255, 240/255, 245/255, 0.75)
|
||||||
border.color: LockscreenService.authFailed ? Theme.red : (secretInput.activeFocus ? Theme.accent : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.18))
|
border.color: LockscreenService.authFailed ? Theme.red : (secretInput.activeFocus ? Theme.accent : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.18))
|
||||||
border.width: LockscreenService.authFailed ? 2 : (secretInput.activeFocus ? 2 : 1)
|
border.width: LockscreenService.authFailed ? 2 : (secretInput.activeFocus ? 2 : 1)
|
||||||
@ -223,255 +223,229 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.margins: 18
|
anchors.margins: 18
|
||||||
spacing: 14
|
spacing: 16
|
||||||
|
|
||||||
// Password Row: Input Field + Submit Button
|
// Centered Password Input Field
|
||||||
RowLayout {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 12
|
implicitHeight: 48
|
||||||
|
radius: 14
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.28)
|
||||||
|
border.color: secretInput.activeFocus ? Qt.rgba(Theme.accent.r, Theme.accent.g, Theme.accent.b, 0.4) : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.12)
|
||||||
|
|
||||||
// Password Visual Placeholder / Input Area
|
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||||
Rectangle {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: 44
|
|
||||||
radius: 12
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.25)
|
|
||||||
border.color: Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.1)
|
|
||||||
|
|
||||||
// Empty State Placeholder Text
|
// Empty State Placeholder Text (Centered)
|
||||||
Text {
|
Text {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.centerIn: parent
|
||||||
anchors.left: parent.left
|
visible: LockscreenService.typedCount === 0 && !LockscreenService.isAuthenticating
|
||||||
anchors.leftMargin: 16
|
text: "Type password to unlock..."
|
||||||
visible: LockscreenService.typedCount === 0 && !LockscreenService.isAuthenticating
|
color: Theme.comment
|
||||||
text: "Type password to unlock..."
|
font.pixelSize: 14
|
||||||
color: Theme.comment
|
}
|
||||||
font.pixelSize: 14
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticating Spinner / Status Text
|
// Authenticating Spinner / Status Text
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: LockscreenService.isAuthenticating
|
visible: LockscreenService.isAuthenticating
|
||||||
text: "Verifying password..."
|
text: "Verifying password..."
|
||||||
color: Theme.accent
|
color: Theme.accent
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: dotsModel
|
id: dotsModel
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: LockscreenService
|
target: LockscreenService
|
||||||
function onTypedCountChanged() {
|
function onTypedCountChanged() {
|
||||||
let targetCount = LockscreenService.typedCount
|
let targetCount = LockscreenService.typedCount
|
||||||
while (dotsModel.count < targetCount) {
|
while (dotsModel.count < targetCount) {
|
||||||
dotsModel.append({ "id": dotsModel.count })
|
dotsModel.append({ "id": dotsModel.count })
|
||||||
}
|
|
||||||
while (dotsModel.count > targetCount) {
|
|
||||||
dotsModel.remove(dotsModel.count - 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
while (dotsModel.count > targetCount) {
|
||||||
|
dotsModel.remove(dotsModel.count - 1)
|
||||||
// ANIMATED TYPING DOTS (Ultra-smooth sliding dot array with add/remove/displaced transitions)
|
|
||||||
Item {
|
|
||||||
id: dotsContainer
|
|
||||||
anchors.centerIn: parent
|
|
||||||
implicitWidth: Math.min(320, dotsModel.count * 26)
|
|
||||||
implicitHeight: 20
|
|
||||||
visible: dotsModel.count > 0 && !LockscreenService.isAuthenticating
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: dotsView
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Math.min(dotsContainer.implicitWidth, count * 26)
|
|
||||||
height: 20
|
|
||||||
orientation: ListView.Horizontal
|
|
||||||
spacing: 12
|
|
||||||
interactive: false
|
|
||||||
model: dotsModel
|
|
||||||
|
|
||||||
add: Transition {
|
|
||||||
ParallelAnimation {
|
|
||||||
NumberAnimation { property: "scale"; from: 0.1; to: 1.0; duration: 250; easing.type: Easing.OutBack; easing.overshoot: 1.6 }
|
|
||||||
NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200; easing.type: Easing.OutCubic }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove: Transition {
|
|
||||||
ParallelAnimation {
|
|
||||||
NumberAnimation { property: "scale"; to: 0.0; duration: 180; easing.type: Easing.InBack }
|
|
||||||
NumberAnimation { property: "opacity"; to: 0.0; duration: 150; easing.type: Easing.OutCubic }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
displaced: Transition {
|
|
||||||
NumberAnimation { properties: "x,y"; duration: 220; easing.type: Easing.OutCubic }
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Item {
|
|
||||||
width: 14
|
|
||||||
height: 14
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: dot
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 7
|
|
||||||
color: index === dotsModel.count - 1 ? Theme.accent : Theme.fg
|
|
||||||
|
|
||||||
Behavior on color { ColorAnimation { duration: 180 } }
|
|
||||||
|
|
||||||
// Inner Glow Core
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 6
|
|
||||||
height: 6
|
|
||||||
radius: 3
|
|
||||||
color: "#ffffff"
|
|
||||||
opacity: index === dotsModel.count - 1 ? 1.0 : 0.6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focus Click Area
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {
|
|
||||||
root.forceActiveFocus()
|
|
||||||
secretInput.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit / Unlock Arrow Button
|
// ANIMATED TYPING DOTS (Centered sliding dot array with add/remove/displaced transitions)
|
||||||
Rectangle {
|
Item {
|
||||||
width: 44
|
id: dotsContainer
|
||||||
height: 44
|
anchors.centerIn: parent
|
||||||
radius: 12
|
implicitWidth: Math.min(320, dotsModel.count * 26)
|
||||||
color: submitMouse.containsMouse ? Theme.accent : Qt.rgba(Theme.accent.r, Theme.accent.g, Theme.accent.b, 0.25)
|
implicitHeight: 20
|
||||||
border.color: Theme.accent
|
visible: dotsModel.count > 0 && !LockscreenService.isAuthenticating
|
||||||
|
|
||||||
Behavior on color { ColorAnimation { duration: 120 } }
|
Behavior on implicitWidth {
|
||||||
|
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "➔"
|
|
||||||
color: submitMouse.containsMouse ? "#ffffff" : Theme.accent
|
|
||||||
font.pixelSize: 18
|
|
||||||
font.weight: Font.Bold
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
ListView {
|
||||||
id: submitMouse
|
id: dotsView
|
||||||
anchors.fill: parent
|
anchors.centerIn: parent
|
||||||
hoverEnabled: true
|
width: Math.min(dotsContainer.implicitWidth, count * 26)
|
||||||
onClicked: LockscreenService.submitPassword()
|
height: 20
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
spacing: 12
|
||||||
|
interactive: false
|
||||||
|
model: dotsModel
|
||||||
|
|
||||||
|
add: Transition {
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation { property: "scale"; from: 0.1; to: 1.0; duration: 250; easing.type: Easing.OutBack; easing.overshoot: 1.6 }
|
||||||
|
NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove: Transition {
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation { property: "scale"; to: 0.0; duration: 180; easing.type: Easing.InBack }
|
||||||
|
NumberAnimation { property: "opacity"; to: 0.0; duration: 150; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displaced: Transition {
|
||||||
|
NumberAnimation { properties: "x,y"; duration: 220; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
width: 14
|
||||||
|
height: 14
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dot
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 7
|
||||||
|
color: index === dotsModel.count - 1 ? Theme.accent : Theme.fg
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: 180 } }
|
||||||
|
|
||||||
|
// Inner Glow Core
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 6
|
||||||
|
height: 6
|
||||||
|
radius: 3
|
||||||
|
color: "#ffffff"
|
||||||
|
opacity: index === dotsModel.count - 1 ? 1.0 : 0.6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus Click Area
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
root.forceActiveFocus()
|
||||||
|
secretInput.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic Typing Status & Feedback Message
|
// Dynamic Auth Error Feedback Message
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: LockscreenService.authFailed
|
visible: LockscreenService.authFailed
|
||||||
|
|
||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
// Auth Error Message Display
|
|
||||||
Text {
|
Text {
|
||||||
text: LockscreenService.authErrorMsg
|
text: LockscreenService.authErrorMsg
|
||||||
color: Theme.red
|
color: Theme.red
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { Layout.preferredHeight: 14 }
|
|
||||||
|
|
||||||
// 4. Session Action Buttons (Power & Unlock)
|
|
||||||
RowLayout {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
// Suspend Button
|
|
||||||
Rectangle {
|
|
||||||
implicitWidth: 110
|
|
||||||
implicitHeight: 38
|
|
||||||
radius: 10
|
|
||||||
color: suspendMouse.containsMouse ? Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.15) : Qt.rgba(0, 0, 0, 0.3)
|
|
||||||
border.color: Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.15)
|
|
||||||
|
|
||||||
|
// Prominent, Large Session Action Buttons (Right underneath Password Input)
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.centerIn: parent
|
Layout.fillWidth: true
|
||||||
spacing: 6
|
spacing: 12
|
||||||
Text { text: "🌙"; font.pixelSize: 13 }
|
|
||||||
Text { text: "Sleep"; color: Theme.fg; font.pixelSize: 12; font.weight: Font.Medium }
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
// Suspend / Sleep Button
|
||||||
id: suspendMouse
|
Rectangle {
|
||||||
anchors.fill: parent
|
Layout.fillWidth: true
|
||||||
hoverEnabled: true
|
implicitHeight: 48
|
||||||
onClicked: {
|
radius: 12
|
||||||
Quickshell.execDetached(["systemctl", "suspend"])
|
color: suspendMouse.containsMouse ? Qt.rgba(Theme.accent.r, Theme.accent.g, Theme.accent.b, 0.25) : Qt.rgba(0, 0, 0, 0.3)
|
||||||
|
border.color: suspendMouse.containsMouse ? Theme.accent : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.12)
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: 150 } }
|
||||||
|
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 8
|
||||||
|
Text { text: "🌙"; font.pixelSize: 16 }
|
||||||
|
Text { text: "Sleep"; color: Theme.fg; font.pixelSize: 14; font.weight: Font.SemiBold }
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: suspendMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: Quickshell.execDetached(["systemctl", "suspend"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reboot Button
|
// Reboot / Restart Button
|
||||||
Rectangle {
|
Rectangle {
|
||||||
implicitWidth: 110
|
Layout.fillWidth: true
|
||||||
implicitHeight: 38
|
implicitHeight: 48
|
||||||
radius: 10
|
radius: 12
|
||||||
color: rebootMouse.containsMouse ? Qt.rgba(Theme.orange.r, Theme.orange.g, Theme.orange.b, 0.25) : Qt.rgba(0, 0, 0, 0.3)
|
color: rebootMouse.containsMouse ? Qt.rgba(Theme.orange.r, Theme.orange.g, Theme.orange.b, 0.3) : Qt.rgba(0, 0, 0, 0.3)
|
||||||
border.color: Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.15)
|
border.color: rebootMouse.containsMouse ? Theme.orange : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.12)
|
||||||
|
|
||||||
RowLayout {
|
Behavior on color { ColorAnimation { duration: 150 } }
|
||||||
anchors.centerIn: parent
|
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||||
spacing: 6
|
|
||||||
Text { text: "🔄"; font.pixelSize: 13 }
|
|
||||||
Text { text: "Restart"; color: Theme.fg; font.pixelSize: 12; font.weight: Font.Medium }
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
RowLayout {
|
||||||
id: rebootMouse
|
anchors.centerIn: parent
|
||||||
anchors.fill: parent
|
spacing: 8
|
||||||
hoverEnabled: true
|
Text { text: "🔄"; font.pixelSize: 16 }
|
||||||
onClicked: SessionService.reboot()
|
Text { text: "Restart"; color: Theme.fg; font.pixelSize: 14; font.weight: Font.SemiBold }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown Button
|
MouseArea {
|
||||||
Rectangle {
|
id: rebootMouse
|
||||||
implicitWidth: 110
|
anchors.fill: parent
|
||||||
implicitHeight: 38
|
hoverEnabled: true
|
||||||
radius: 10
|
onClicked: SessionService.reboot()
|
||||||
color: powerMouse.containsMouse ? Qt.rgba(Theme.red.r, Theme.red.g, Theme.red.b, 0.25) : Qt.rgba(0, 0, 0, 0.3)
|
}
|
||||||
border.color: Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.15)
|
}
|
||||||
|
|
||||||
RowLayout {
|
// Shutdown / Power Off Button
|
||||||
anchors.centerIn: parent
|
Rectangle {
|
||||||
spacing: 6
|
Layout.fillWidth: true
|
||||||
Text { text: "⚡"; font.pixelSize: 13 }
|
implicitHeight: 48
|
||||||
Text { text: "Power Off"; color: Theme.fg; font.pixelSize: 12; font.weight: Font.Medium }
|
radius: 12
|
||||||
}
|
color: powerMouse.containsMouse ? Qt.rgba(Theme.red.r, Theme.red.g, Theme.red.b, 0.3) : Qt.rgba(0, 0, 0, 0.3)
|
||||||
|
border.color: powerMouse.containsMouse ? Theme.red : Qt.rgba(Theme.fg.r, Theme.fg.g, Theme.fg.b, 0.12)
|
||||||
|
|
||||||
MouseArea {
|
Behavior on color { ColorAnimation { duration: 150 } }
|
||||||
id: powerMouse
|
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
RowLayout {
|
||||||
onClicked: SessionService.shutdown()
|
anchors.centerIn: parent
|
||||||
|
spacing: 8
|
||||||
|
Text { text: "⏻"; font.pixelSize: 16; color: Theme.red }
|
||||||
|
Text { text: "Power Off"; color: Theme.fg; font.pixelSize: 14; font.weight: Font.SemiBold }
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: powerMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: SessionService.shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user