Files
FWS-ISO/configs/releng/airootfs/usr/share/sddm/themes/fws/Main.qml
T
nocode 24370461ea feat(sddm): add fws login theme for kde xfce and hyprland
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.
2026-07-04 00:00:05 +02:00

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
}
}