24370461ea
Introduce a new SDDM theme "fws" designed for FWS with support for KDE, XFCE, and Hyprland desktop environments. The theme is built using pure QtQuick and QtQuick.Controls (Basic style) with no additional dependencies beyond what SDDM already requires. It includes: - Main.qml: Custom login screen with clock, date, user/password fields, session selector, and power controls - metadata.desktop: Theme metadata and configuration - theme.conf: Default configuration with customizable accent color and gradient colors The design uses a dark theme with accent colors and supports capslock detection and login error handling.
250 lines
8.1 KiB
QML
250 lines
8.1 KiB
QML
// Thème SDDM « fws » — écran de connexion FWS (KDE / XFCE / Hyprland).
|
|
//
|
|
// VOLONTAIREMENT en pur QtQuick + QtQuick.Controls (style Basic) : ces
|
|
// modules arrivent avec qt6-declarative, dépendance de sddm lui-même →
|
|
// AUCUN paquet supplémentaire requis (pas de Breeze/plasma-workspace, pas
|
|
// de QtGraphicalEffects — supprimé en Qt6). Le greeter fournit en contexte
|
|
// les objets sddm, userModel, sessionModel, keyboard et config (theme.conf,
|
|
// surchargé par theme.conf.user écrit par le %post : accent selon le DE).
|
|
import QtQuick
|
|
import QtQuick.Controls.Basic
|
|
|
|
Rectangle {
|
|
id: root
|
|
width: 1280
|
|
height: 800
|
|
|
|
readonly property color accent: config.accent || "#3daee9"
|
|
readonly property color fieldBg: "#2a2a44"
|
|
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: config.colorTop || "#1a1a2e" }
|
|
GradientStop { position: 1.0; color: config.colorBottom || "#16213e" }
|
|
}
|
|
|
|
Connections {
|
|
target: sddm
|
|
function onLoginFailed() {
|
|
errorLabel.text = "Échec de la connexion — vérifiez le mot de passe"
|
|
passwordField.text = ""
|
|
passwordField.forceActiveFocus()
|
|
}
|
|
function onLoginSucceeded() {
|
|
errorLabel.text = ""
|
|
}
|
|
}
|
|
|
|
function doLogin() {
|
|
errorLabel.text = ""
|
|
sddm.login(userField.text, passwordField.text, sessionBox.currentIndex)
|
|
}
|
|
|
|
// --- Horloge -----------------------------------------------------------
|
|
Timer {
|
|
interval: 1000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
var now = new Date()
|
|
clockLabel.text = Qt.formatTime(now, "hh:mm")
|
|
dateLabel.text = Qt.formatDate(now, "dddd d MMMM yyyy")
|
|
}
|
|
Component.onCompleted: triggered()
|
|
}
|
|
|
|
Column {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
anchors.topMargin: parent.height * 0.10
|
|
spacing: 4
|
|
|
|
Text {
|
|
id: clockLabel
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: "#f0f0f5"
|
|
font.pixelSize: 84
|
|
font.weight: Font.Light
|
|
}
|
|
Text {
|
|
id: dateLabel
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: "#a0a0b8"
|
|
font.pixelSize: 20
|
|
font.capitalization: Font.Capitalize
|
|
}
|
|
}
|
|
|
|
// --- Carte de connexion --------------------------------------------------
|
|
Rectangle {
|
|
id: card
|
|
anchors.centerIn: parent
|
|
anchors.verticalCenterOffset: parent.height * 0.08
|
|
width: 400
|
|
height: cardContent.implicitHeight + 56
|
|
radius: 14
|
|
color: "#232338"
|
|
border.color: Qt.rgba(1, 1, 1, 0.10)
|
|
border.width: 1
|
|
|
|
Column {
|
|
id: cardContent
|
|
anchors.centerIn: parent
|
|
width: parent.width - 56
|
|
spacing: 14
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: config.greeting || "Bienvenue sur FWS"
|
|
color: "#f0f0f5"
|
|
font.pixelSize: 22
|
|
font.weight: Font.Medium
|
|
}
|
|
|
|
Rectangle { width: 44; height: 3; radius: 1.5; color: accent
|
|
anchors.horizontalCenter: parent.horizontalCenter }
|
|
|
|
TextField {
|
|
id: userField
|
|
width: parent.width
|
|
text: userModel.lastUser
|
|
placeholderText: "Utilisateur"
|
|
placeholderTextColor: "#7d7d95"
|
|
color: "#f0f0f5"
|
|
font.pixelSize: 15
|
|
leftPadding: 14
|
|
background: Rectangle {
|
|
radius: 8
|
|
color: fieldBg
|
|
border.color: userField.activeFocus ? accent : "transparent"
|
|
border.width: 2
|
|
}
|
|
onAccepted: passwordField.forceActiveFocus()
|
|
}
|
|
|
|
TextField {
|
|
id: passwordField
|
|
width: parent.width
|
|
placeholderText: "Mot de passe"
|
|
placeholderTextColor: "#7d7d95"
|
|
color: "#f0f0f5"
|
|
font.pixelSize: 15
|
|
leftPadding: 14
|
|
echoMode: TextInput.Password
|
|
focus: true
|
|
background: Rectangle {
|
|
radius: 8
|
|
color: fieldBg
|
|
border.color: passwordField.activeFocus ? accent : "transparent"
|
|
border.width: 2
|
|
}
|
|
onAccepted: doLogin()
|
|
}
|
|
|
|
Text {
|
|
visible: keyboard.capsLock
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: "⚠ Verrouillage majuscules activé"
|
|
color: "#e6c07b"
|
|
font.pixelSize: 13
|
|
}
|
|
|
|
Text {
|
|
id: errorLabel
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
wrapMode: Text.WordWrap
|
|
color: "#e06c75"
|
|
font.pixelSize: 13
|
|
}
|
|
|
|
Button {
|
|
id: loginButton
|
|
width: parent.width
|
|
height: 44
|
|
onClicked: doLogin()
|
|
contentItem: Text {
|
|
text: "Se connecter"
|
|
color: "#ffffff"
|
|
font.pixelSize: 16
|
|
font.weight: Font.Medium
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
background: Rectangle {
|
|
radius: 8
|
|
color: loginButton.down ? Qt.darker(accent, 1.25)
|
|
: loginButton.hovered ? Qt.lighter(accent, 1.10)
|
|
: accent
|
|
}
|
|
}
|
|
|
|
ComboBox {
|
|
id: sessionBox
|
|
width: parent.width
|
|
model: sessionModel
|
|
currentIndex: sessionModel.lastIndex
|
|
textRole: "name"
|
|
font.pixelSize: 13
|
|
contentItem: Text {
|
|
leftPadding: 14
|
|
text: sessionBox.displayText
|
|
color: "#a0a0b8"
|
|
font.pixelSize: 13
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
background: Rectangle {
|
|
radius: 8
|
|
color: "transparent"
|
|
border.color: Qt.rgba(1, 1, 1, 0.15)
|
|
border.width: 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Boutons d'alimentation ----------------------------------------------
|
|
// PAS de Repeater avec des fonctions dans un modèle JS : en Qt6 elles ne
|
|
// survivent pas toujours à la conversion QVariant (clic silencieusement
|
|
// inopérant). Deux boutons explicites via un composant inline.
|
|
component PowerButton: Button {
|
|
id: powerButton
|
|
property string label: ""
|
|
height: 36
|
|
contentItem: Text {
|
|
text: powerButton.label
|
|
color: powerButton.hovered ? "#f0f0f5" : "#a0a0b8"
|
|
font.pixelSize: 14
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
leftPadding: 14
|
|
rightPadding: 14
|
|
}
|
|
background: Rectangle {
|
|
radius: 8
|
|
color: powerButton.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
|
|
border.color: Qt.rgba(1, 1, 1, 0.15)
|
|
border.width: 1
|
|
}
|
|
}
|
|
|
|
Row {
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
anchors.margins: 24
|
|
spacing: 10
|
|
|
|
PowerButton { label: "Redémarrer"; onClicked: sddm.reboot() }
|
|
PowerButton { label: "Éteindre"; onClicked: sddm.powerOff() }
|
|
}
|
|
|
|
// Nom de la machine, discret, en bas à gauche.
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.bottom: parent.bottom
|
|
anchors.margins: 24
|
|
text: sddm.hostName
|
|
color: "#5d5d78"
|
|
font.pixelSize: 13
|
|
}
|
|
}
|