265 lines
8.3 KiB
QML
265 lines
8.3 KiB
QML
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
// Where the lock screen is a program of the user's (Hyprland, Niri): lock
|
|
// with face-unlock's own, with the bubble, or keep that program, which then
|
|
// shows a line of text (hyprlock). Each choice shows the user's screen as it
|
|
// would look: face-unlock's lock screen live, and their own rebuilt from its
|
|
// config (see LockPreview). The pick goes back to the menu, which carries
|
|
// it out.
|
|
|
|
import QtQuick
|
|
import QtQuick.Effects
|
|
import QtQuick.Window
|
|
import FaceUnlock
|
|
|
|
Window {
|
|
id: window
|
|
|
|
// "own", "yours", or empty when there is none yet.
|
|
required property string current
|
|
// The user's lock screen (see LockPreview::locker) and what it shows.
|
|
required property string locker
|
|
required property var widgets
|
|
// The screen the pictures show, and the parts of face-unlock's own.
|
|
required property size screenSize
|
|
required property url ownWallpaper
|
|
required property var lock
|
|
required property var bubble
|
|
// What was picked, empty when the window was closed.
|
|
property string answer: ""
|
|
property string selected: current
|
|
|
|
function pick() {
|
|
if (selected.length > 0) {
|
|
answer = selected
|
|
close()
|
|
}
|
|
}
|
|
|
|
// One fixed size, so tiling compositors float it (see Enroll). The
|
|
// height follows the texts, whose length depends on the language. It
|
|
// is taken from them rather than from the Row and Column, which only lay
|
|
// out once the window shows, and the agent shows it after that.
|
|
readonly property int fitHeight: Math.ceil(36 + heading.height + 10 + intro.height + 28 + Math.max(own.needed, yours.needed) + 94)
|
|
width: 800
|
|
height: fitHeight
|
|
minimumWidth: 800
|
|
maximumWidth: 800
|
|
minimumHeight: fitHeight
|
|
maximumHeight: fitHeight
|
|
visible: false
|
|
color: Theme.panel
|
|
title: i18n("Choose your lock screen")
|
|
|
|
Component {
|
|
id: ownScene
|
|
LockScreen {
|
|
lock: window.lock
|
|
bubble: window.bubble
|
|
primary: true
|
|
wallpaper: window.ownWallpaper
|
|
interactive: false
|
|
}
|
|
}
|
|
Component {
|
|
id: yoursScene
|
|
LockPreview {
|
|
widgets: window.widgets
|
|
}
|
|
}
|
|
|
|
// One of the two: the screen, a radio button with the name, what it means.
|
|
component Choice: Rectangle {
|
|
id: card
|
|
|
|
required property string style
|
|
required property Component scene
|
|
required property string name
|
|
required property string about
|
|
readonly property bool chosen: window.selected === style
|
|
// The height its text needs; both take the larger one.
|
|
readonly property real needed: body.y + body.height + 20
|
|
|
|
width: 364
|
|
radius: 18
|
|
color: area.containsMouse && !chosen ? Qt.lighter(Theme.surface, 1.25) : Theme.surface
|
|
border.width: 2
|
|
border.color: chosen ? Theme.accent : "transparent"
|
|
Behavior on border.color { ColorAnimation { duration: 150 } }
|
|
Behavior on color { ColorAnimation { duration: 120 } }
|
|
|
|
// The whole screen, made small: filling the picture, cut at the
|
|
// sides or at the top and bottom.
|
|
Item {
|
|
id: picture
|
|
x: 14
|
|
y: 14
|
|
width: parent.width - 28
|
|
height: Math.round(width * 10 / 16)
|
|
clip: true
|
|
layer.enabled: true
|
|
layer.effect: MultiEffect {
|
|
maskEnabled: true
|
|
maskSource: mask
|
|
}
|
|
|
|
Loader {
|
|
sourceComponent: card.scene
|
|
width: window.screenSize.width
|
|
height: window.screenSize.height
|
|
transformOrigin: Item.TopLeft
|
|
scale: Math.max(picture.width / width, picture.height / height)
|
|
x: (picture.width - width * scale) / 2
|
|
y: (picture.height - height * scale) / 2
|
|
}
|
|
}
|
|
Rectangle {
|
|
id: mask
|
|
width: picture.width
|
|
height: picture.height
|
|
radius: 10
|
|
visible: false
|
|
layer.enabled: true
|
|
}
|
|
|
|
// A radio button: a ring, filled when picked.
|
|
Rectangle {
|
|
id: radio
|
|
x: 18
|
|
y: title.y + 3
|
|
width: 18
|
|
height: 18
|
|
radius: 9
|
|
color: "transparent"
|
|
border.width: 2
|
|
border.color: card.chosen ? Theme.accent : Theme.textSecondary
|
|
Rectangle {
|
|
anchors.centerIn: parent
|
|
width: 8
|
|
height: 8
|
|
radius: 4
|
|
color: Theme.accent
|
|
visible: card.chosen
|
|
}
|
|
}
|
|
Text {
|
|
id: title
|
|
anchors.top: picture.bottom
|
|
anchors.topMargin: 16
|
|
x: radio.x + radio.width + 10
|
|
width: parent.width - x - 18
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.textPrimary
|
|
font.pixelSize: 16
|
|
font.weight: Font.DemiBold
|
|
text: card.name
|
|
}
|
|
Text {
|
|
id: body
|
|
anchors.top: title.bottom
|
|
anchors.topMargin: 8
|
|
x: 18
|
|
width: parent.width - 36
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.textDetail
|
|
font.pixelSize: 13
|
|
lineHeight: 1.15
|
|
text: card.about
|
|
}
|
|
|
|
MouseArea {
|
|
id: area
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: window.selected = card.style
|
|
onDoubleClicked: {
|
|
window.selected = card.style
|
|
window.pick()
|
|
}
|
|
}
|
|
}
|
|
|
|
Column {
|
|
id: head
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 36
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: parent.width - 96
|
|
spacing: 10
|
|
|
|
Text {
|
|
id: heading
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
color: Theme.textPrimary
|
|
font.pixelSize: 26
|
|
font.weight: Font.Bold
|
|
text: i18n("Your lock screen")
|
|
}
|
|
Text {
|
|
id: intro
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.textSecondary
|
|
font.pixelSize: 13
|
|
font.weight: Font.Medium
|
|
lineHeight: 1.15
|
|
text: i18n("Your desktop leaves the lock screen to a program of your choice. Pick how face unlock shows up there. You can change it later under Settings.")
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: cards
|
|
anchors.top: head.bottom
|
|
anchors.topMargin: 28
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: 24
|
|
focus: true
|
|
|
|
Keys.onLeftPressed: window.selected = "own"
|
|
Keys.onRightPressed: window.selected = "yours"
|
|
Keys.onReturnPressed: window.pick()
|
|
Keys.onEnterPressed: window.pick()
|
|
Keys.onEscapePressed: window.close()
|
|
|
|
Choice {
|
|
id: own
|
|
height: Math.max(own.needed, yours.needed)
|
|
style: "own"
|
|
scene: ownScene
|
|
name: i18n("face-unlock's lock screen")
|
|
about: i18n("The bubble at the top, the time and your wallpaper. Your shortcut and idle lock then run face-unlock lock.")
|
|
}
|
|
Choice {
|
|
id: yours
|
|
height: own.height
|
|
style: "yours"
|
|
scene: yoursScene
|
|
name: i18n("Keep your lock screen")
|
|
about: window.locker === "hyprlock"
|
|
? i18n("It stays as it is. hyprlock shows a line of text at the top instead of the bubble. Enter on the empty password field scans.")
|
|
: i18n("It stays as it is, without the bubble. Enter on the empty password field scans.")
|
|
}
|
|
}
|
|
|
|
Row {
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 32
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: 12
|
|
|
|
PillButton {
|
|
primary: false
|
|
text: i18n("Cancel")
|
|
onClicked: window.close()
|
|
}
|
|
PillButton {
|
|
enabled: window.selected.length > 0
|
|
text: i18n("Continue")
|
|
onClicked: window.pick()
|
|
}
|
|
}
|
|
}
|