pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Config import qs.Components import qs.Helpers import qs.Services ColumnLayout { id: root required property var greeter anchors.fill: parent anchors.margins: Tokens.padding.large spacing: Tokens.spacing.small CustomText { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight font.family: Config.appearance.font.family.mono font.weight: 500 text: root.greeter.users.length > 0 ? qsTr("%1 user%2").arg(root.greeter.users.length).arg(root.greeter.users.length === 1 ? "" : "s") : qsTr("Users") } CustomClippingRect { Layout.fillHeight: true Layout.fillWidth: true color: "transparent" radius: Tokens.rounding.small Loader { active: opacity > 0 anchors.centerIn: parent opacity: root.greeter.users.length > 0 ? 0 : 1 Behavior on opacity { Anim { duration: Tokens.anim.durations.extraLarge } } sourceComponent: ColumnLayout { spacing: Tokens.spacing.largeIncreased MaterialIcon { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant fill: 1 font.pointSize: Tokens.font.size.extraLarge * 2 text: "account_circle" } CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.large font.weight: 500 text: qsTr("No Users Found") } } } ListView { id: users anchors.fill: parent clip: true currentIndex: root.greeter.selectedUser ? root.greeter.users.indexOf(root.greeter.selectedUser) : -1 highlightFollowsCurrentItem: false model: root.greeter.users spacing: Tokens.spacing.small delegate: CustomRect { id: user required property int index required property var modelData anchors.left: parent?.left anchors.right: parent?.right implicitHeight: row.implicitHeight + Tokens.padding.small * 2 radius: Tokens.rounding.medium - Tokens.padding.small StateLayer { onClicked: { root.greeter.selectUser(modelData.username); } } RowLayout { id: row anchors.fill: parent anchors.margins: Tokens.padding.small spacing: Tokens.spacing.medium CustomClippingRect { Layout.preferredHeight: 50 Layout.preferredWidth: 50 radius: Tokens.rounding.full MaterialIcon { anchors.centerIn: parent color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant fill: 1 font.pointSize: Tokens.font.size.extraLarge text: modelData.kind === "x11" ? "tv" : "account_circle" } CachingImage { anchors.fill: parent path: modelData.face } } ColumnLayout { Layout.fillWidth: true spacing: Tokens.spacing.small / 2 CustomText { Layout.fillWidth: true color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface elide: Text.ElideRight font.pointSize: Tokens.font.size.normal font.weight: 600 text: modelData.username } } } } highlight: CustomRect { color: Colors.palette.m3primary implicitHeight: users.currentItem?.implicitHeight ?? 0 implicitWidth: users.width radius: Tokens.rounding.medium - Tokens.padding.small y: users.currentItem?.y ?? 0 Behavior on y { Anim { duration: Tokens.anim.durations.expressiveDefaultEffects easing: Tokens.anim.expressiveDefaultEffects } } } } } }