Files

405 lines
14 KiB
QML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
Costruttivista — tema SDDM
Schermata di accesso in stile costruttivista sovietico per SDDM.
Autosufficiente: solo QtQuick 2.15 e QtQuick.Controls 2.15, nessuna dipendenza esterna.
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import "fauxcyrillic.js" as Faux
Rectangle {
id: root
color: "#101012"
width: 1920
height: 1080
readonly property color red: "#d83a28"
readonly property color cream: "#f0dfba"
readonly property color dark: "#181719"
readonly property color panelBg: "#d9151517"
readonly property color paper: "#f6f1e5"
// Font pseudo-cirillico (Russo One, OFL) incluso nel tema.
FontLoader {
id: themeFont
source: "assets/fonts/RussoOne-Regular.ttf"
}
// Utente selezionato dalla lista (quando il modello espone utenti).
property string selectedUser: userModel.lastUser || ""
// Data in italiano senza dipendere dalla locale del greeter.
function italianDate(d) {
var days = ["DOMENICA", "LUNEDÌ", "MARTEDÌ", "MERCOLEDÌ", "GIOVEDÌ", "VENERDÌ", "SABATO"]
var months = ["GENNAIO", "FEBBRAIO", "MARZO", "APRILE", "MAGGIO", "GIUGNO", "LUGLIO", "AGOSTO", "SETTEMBRE", "OTTOBRE", "NOVEMBRE", "DICEMBRE"]
return days[d.getDay()] + " " + d.getDate() + " " + months[d.getMonth()] + " " + d.getFullYear()
}
function tryLogin() {
var username = userModel.count > 0 ? root.selectedUser : userField.text
if (username.length === 0) {
errorText.text = Faux.apply("INSERISCI L'UTENTE")
shake.start()
return
}
errorText.text = ""
sddm.login(username, passField.text, sessionCombo.currentIndex)
}
Item {
id: ui
anchors.fill: parent
opacity: 0
// ---------- sfondo ----------
Image {
id: background
anchors.fill: parent
source: "assets/sfondo_costruttivista_fhd.png"
fillMode: Image.PreserveAspectCrop
asynchronous: true
cache: true
}
Rectangle {
anchors.fill: parent
color: "#12000000"
opacity: overlayFade.value
}
// ---------- accenti geometrici ----------
Item {
id: accents
anchors.fill: parent
Rectangle {
id: redBar
x: parent.width * 0.07
y: parent.height * 0.15
width: Math.max(5, parent.width * 0.008)
height: parent.height * 0.27
color: root.red
opacity: 0.9
transform: Translate { id: redShift; y: -root.height * 0.10 }
}
Rectangle {
id: creamLine
x: parent.width * 0.07
y: parent.height * 0.44
width: parent.width * 0.20
height: Math.max(2, parent.height * 0.004)
color: root.cream
opacity: 0.85
transform: Translate { id: lineShift; x: -root.width * 0.12 }
}
Rectangle {
id: darkBar
x: parent.width * 0.82
y: parent.height * 0.60
width: Math.max(4, parent.width * 0.005)
height: parent.height * 0.20
color: root.dark
opacity: 0.75
transform: Translate { id: darkShift; y: root.height * 0.09 }
}
}
// ---------- orologio ----------
Rectangle {
id: clockBackdrop
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Math.max(36, root.height * 0.055)
width: clockBlock.width + Math.max(36, root.width * 0.02)
height: clockBlock.height + Math.max(22, root.height * 0.022)
color: "#66101012"
border.color: "#33f0dfba"
border.width: 1
Column {
id: clockBlock
anchors.centerIn: parent
spacing: Math.max(2, root.height * 0.004)
Text {
id: clockText
anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatTime(new Date(), "HH:mm")
color: root.cream
font.family: themeFont.name
font.pixelSize: Math.max(44, Math.min(root.width * 0.05, 88))
font.bold: true
font.letterSpacing: 4
}
Text {
id: dateText
anchors.horizontalCenter: parent.horizontalCenter
text: Faux.apply(root.italianDate(new Date()))
color: "#ef6a55"
font.family: themeFont.name
font.pixelSize: Math.max(13, Math.min(root.width * 0.014, 22))
font.bold: true
font.letterSpacing: 2
}
Timer {
interval: 1000
repeat: true
running: true
onTriggered: {
clockText.text = Qt.formatTime(new Date(), "HH:mm")
dateText.text = Faux.apply(root.italianDate(new Date()))
}
}
}
}
// ---------- pannello di accesso ----------
Item {
id: panelHost
anchors.centerIn: parent
width: panel.width
height: panel.height
transform: Translate { id: panelShift; x: 0 }
Rectangle {
id: panel
width: Math.min(root.width * 0.40, 500)
height: panelCol.implicitHeight + Math.max(52, root.height * 0.056)
color: root.panelBg
border.color: "#66f0dfba"
border.width: Math.max(1, root.height * 0.002)
Rectangle {
width: Math.max(8, panel.width * 0.02)
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
color: root.red
}
Column {
id: panelCol
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.leftMargin: Math.max(26, root.height * 0.028)
anchors.rightMargin: Math.max(26, root.height * 0.028)
anchors.topMargin: Math.max(26, root.height * 0.028)
spacing: Math.max(14, root.height * 0.016)
// intestazione: marca + titolo
RowLayout {
width: parent.width
spacing: Math.max(16, root.width * 0.011)
Mark {
Layout.preferredWidth: Math.max(58, Math.min(panel.width * 0.15, 96))
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter
}
Column {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
spacing: 2
Text {
text: "АССЭSSО"
color: root.cream
font.family: themeFont.name
font.pixelSize: Math.max(20, Math.min(root.width * 0.024, 34))
font.bold: true
font.letterSpacing: 3
}
Text {
text: Faux.apply("INSERISCI LE CREDENZIALI")
color: "#e85a48"
font.family: themeFont.name
font.pixelSize: Math.max(10, Math.min(root.width * 0.011, 15))
font.bold: true
font.letterSpacing: 1
}
}
}
// lista utenti con avatar (solo se il modello espone utenti)
Item {
width: parent.width
height: userListRow.height
UserList {
id: userListRow
anchors.horizontalCenter: parent.horizontalCenter
onUserSelected: root.selectedUser = name
}
}
// campo utente (solo se non ci sono utenti da selezionare)
Field {
id: userField
visible: userModel.count === 0
label: "UTENTE"
text: userModel.lastUser || ""
}
// campo password
Field {
id: passField
label: "PASSWORD"
password: true
onAccepted: root.tryLogin()
}
// selettore sessione
Combo {
id: sessionCombo
label: "SESSIONE"
model: sessionModel
textRole: "name"
currentIndex: sessionModel.lastIndex >= 0 ? sessionModel.lastIndex : 0
}
// messaggio di errore
Text {
id: errorText
width: parent.width
text: ""
color: root.red
font.bold: true
font.letterSpacing: 1
font.family: themeFont.name
font.pixelSize: Math.max(11, Math.min(root.width * 0.012, 16))
visible: text.length > 0
wrapMode: Text.WordWrap
}
// pulsante di accesso
Rectangle {
id: loginButton
width: parent.width
height: Math.max(42, root.height * 0.05)
color: root.red
border.color: root.cream
border.width: 1
Text {
anchors.centerIn: parent
text: Faux.apply("ENTRA")
color: root.paper
font.bold: true
font.letterSpacing: 3
font.family: themeFont.name
font.pixelSize: Math.max(14, Math.min(root.width * 0.015, 20))
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: root.tryLogin()
onPressed: loginButton.color = Qt.darker(root.red, 1.3)
onReleased: loginButton.color = root.red
}
}
// separatore
Rectangle {
width: parent.width
height: 2
color: "#66f0dfba"
}
// pulsanti di sistema
RowLayout {
width: parent.width
spacing: Math.max(8, root.width * 0.006)
PowerButton {
Layout.fillWidth: true
label: "SOSPENDI"
enabled: sddm.canSuspend
onClicked: sddm.suspend()
}
PowerButton {
Layout.fillWidth: true
label: "RIAVVIA"
enabled: sddm.canReboot
onClicked: sddm.reboot()
}
PowerButton {
Layout.fillWidth: true
label: "SPEGNI"
enabled: sddm.canPowerOff
onClicked: sddm.powerOff()
}
}
}
}
}
}
// ---------- animazioni ----------
QtObject { id: overlayFade; property real value: 0.0 }
ParallelAnimation {
id: intro
NumberAnimation { target: ui; property: "opacity"; from: 0; to: 1; duration: 700; easing.type: Easing.OutCubic }
NumberAnimation { target: overlayFade; property: "value"; from: 0; to: 1; duration: 900 }
NumberAnimation { target: redShift; property: "y"; to: 0; duration: 850; easing.type: Easing.OutCubic }
NumberAnimation { target: lineShift; property: "x"; to: 0; duration: 950; easing.type: Easing.OutCubic }
NumberAnimation { target: darkShift; property: "y"; to: 0; duration: 1050; easing.type: Easing.OutCubic }
}
SequentialAnimation {
id: shake
NumberAnimation { target: panelShift; property: "x"; to: -14; duration: 45 }
NumberAnimation { target: panelShift; property: "x"; to: 14; duration: 45 }
NumberAnimation { target: panelShift; property: "x"; to: -10; duration: 45 }
NumberAnimation { target: panelShift; property: "x"; to: 10; duration: 45 }
NumberAnimation { target: panelShift; property: "x"; to: 0; duration: 45 }
}
NumberAnimation {
id: leave
target: root
property: "opacity"
to: 0
duration: 500
easing.type: Easing.InOutQuad
}
Component.onCompleted: {
intro.start()
focusTimer.start()
}
Timer {
id: focusTimer
interval: 200
onTriggered: {
if (userModel.count > 0) {
passField.input.forceActiveFocus()
} else {
userField.input.forceActiveFocus()
}
}
}
Connections {
target: sddm
function onLoginFailed() {
errorText.text = Faux.apply("ACCESSO NEGATO")
passField.text = ""
shake.start()
}
function onLoginSucceeded() {
leave.start()
}
}
}