add about page in settings
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 13s
Python / test (pull_request) Successful in 53s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m35s
C++ / build (pull_request) Successful in 2m32s

This commit is contained in:
2026-06-29 23:54:54 +02:00
parent 3f7bbc01aa
commit 437f935f73
6 changed files with 278 additions and 6 deletions
+64 -6
View File
@@ -1,17 +1,30 @@
pragma Singleton
import qs.Config
import QtQuick
import Quickshell
import Quickshell.Io
import QtQuick
import qs.Config
import qs.Paths
Singleton {
id: root
property string boardName
property string boardVendor
readonly property string device: {
if (!boardName)
return boardVendor;
if (!boardVendor || boardName.toLowerCase().startsWith(boardVendor.toLowerCase()))
return boardName;
return `${boardVendor} ${boardName}`;
}
property string firmware
property string hostname
property bool isDefaultLogo: true
property string kernel
property string osId
property list<string> osIdLike
property string osLogo
property string osLogo: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/logo.svg`)
property string osName
property string osPrettyName
readonly property string shell: Quickshell.env("SHELL").split("/").pop()
@@ -19,6 +32,12 @@ Singleton {
readonly property string user: Quickshell.env("USER")
readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP")
function sanitiseDmi(s: string): string {
const t = s.trim();
const junk = ["to be filled by o.e.m.", "system product name", "system manufacturer", "system version", "default string", "o.e.m.", "not specified", "not applicable", "unknown", "none", ""];
return junk.includes(t.toLowerCase()) ? "" : t;
}
FileView {
id: osRelease
@@ -35,7 +54,10 @@ Singleton {
root.osIdLike = fd("ID_LIKE").split(" ");
const logo = Quickshell.iconPath(fd("LOGO"), true);
if (Config.general.logo) {
if (Config.general.logo === "zshell") {
root.osLogo = Qt.resolvedUrl(`${Quickshell.shellDir}/assets/logo.svg`);
root.isDefaultLogo = true;
} else if (Config.general.logo) {
root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo);
root.isDefaultLogo = false;
} else if (logo) {
@@ -53,6 +75,39 @@ Singleton {
target: Config.general
}
FileView {
path: "/proc/sys/kernel/osrelease"
onLoaded: root.kernel = text().trim()
}
FileView {
path: "/proc/sys/kernel/hostname"
onLoaded: root.hostname = text().trim()
}
FileView {
path: "/sys/class/dmi/id/sys_vendor"
printErrors: false
onLoaded: root.boardVendor = root.sanitiseDmi(text())
}
FileView {
path: "/sys/class/dmi/id/product_name"
printErrors: false
onLoaded: root.boardName = root.sanitiseDmi(text())
}
FileView {
path: "/sys/class/dmi/id/bios_version"
printErrors: false
onLoaded: root.firmware = root.sanitiseDmi(text())
}
Timer {
interval: 15000
repeat: true
@@ -69,12 +124,15 @@ Singleton {
onLoaded: {
const up = parseInt(text().split(" ")[0] ?? 0);
const hours = Math.floor(up / 3600);
const days = Math.floor(up / 86400);
const hours = Math.floor((up % 86400) / 3600);
const minutes = Math.floor((up % 3600) / 60);
let str = "";
if (days > 0)
str += `${days} day${days === 1 ? "" : "s"}`;
if (hours > 0)
str += `${hours} hour${hours === 1 ? "" : "s"}`;
str += `${str ? ", " : ""}${hours} hour${hours === 1 ? "" : "s"}`;
if (minutes > 0 || !str)
str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`;
root.uptime = str;
+78
View File
@@ -0,0 +1,78 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
ConnectedRect {
id: root
property string icon
property color iconColor: DynamicColors.palette.m3onSurfaceVariant
property alias label: label.text
property Component leadingComponent: icon ? iconComp : null
property string subtext
property alias value: value.text
Layout.fillWidth: true
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2
Component {
id: iconComp
MaterialIcon {
color: root.iconColor
font.pointSize: Appearance.font.size.small
text: root.icon
}
}
RowLayout {
id: rowLayout
anchors.fill: parent
anchors.leftMargin: Appearance.padding.largeIncreased
anchors.margins: Appearance.padding.larger
anchors.rightMargin: Appearance.padding.largeIncreased
spacing: Appearance.spacing.small
Loader {
active: root.leadingComponent
sourceComponent: root.leadingComponent
visible: root.leadingComponent
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
CustomText {
id: label
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
}
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: root.subtext
visible: root.subtext
}
}
CustomText {
id: value
Layout.maximumWidth: root.width / 2
color: DynamicColors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
horizontalAlignment: Text.AlignRight
}
}
}
+10
View File
@@ -150,6 +150,16 @@ QtObject {
}
}
}
},
// About
Component {
StackPage {
Component {
AboutPage {
}
}
}
}
]
readonly property Component placeholderComp: Component {
+6
View File
@@ -60,5 +60,11 @@ Singleton {
description: qsTr("Poll intervals, audio and brightness increments"),
category: "shell"
},
{
name: qsTr("About"),
icon: "info",
description: qsTr("System information"),
category: "about"
},
]
}
+117
View File
@@ -0,0 +1,117 @@
import QtQuick
import QtQuick.Layouts
import Quickshell.Io
import ZShell
import qs.Modules.SettingsNew.Common
import qs.Config
import qs.Helpers
import qs.Components
PageBase {
id: root
property string cliVersion
readonly property int pluginCount: 0
property string quickshellVersion
title: qsTr("About")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
Process {
command: ["quickshell", "--version"]
running: true
stdout: StdioCollector {
onStreamFinished: root.quickshellVersion = text.trim().split(" ")[1] ?? ""
}
}
ConnectedRect {
Layout.fillWidth: true
first: true
implicitHeight: hero.implicitHeight + Appearance.padding.extraLarge * 2
last: true
ColumnLayout {
id: hero
anchors.centerIn: parent
spacing: Appearance.spacing.small
width: parent.width - Appearance.padding.largeIncreased * 2
CustomText {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Appearance.spacing.small
font.pointSize: Appearance.font.size.large
text: "ZShell"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3onSurfaceVariant
font: Appearance.font.body.medium
text: ZUtils.version ? `v${ZUtils.version}` : "…"
}
}
}
// System
SectionHeader {
text: qsTr("System")
}
InfoRow {
first: true
label: qsTr("Hostname")
value: SystemInfo.hostname
}
InfoRow {
label: qsTr("Device")
value: SystemInfo.device
}
InfoRow {
label: qsTr("Distro")
value: SystemInfo.osPrettyName || SystemInfo.osName
}
InfoRow {
label: qsTr("Kernel")
value: SystemInfo.kernel
}
InfoRow {
label: qsTr("Firmware")
last: true
value: SystemInfo.firmware
}
// Software
SectionHeader {
text: qsTr("Software")
}
InfoRow {
first: true
label: qsTr("Shell")
value: ZUtils.version || "…"
}
InfoRow {
label: qsTr("Quickshell")
value: root.quickshellVersion || "…"
}
InfoRow {
label: qsTr("Qt")
last: true
value: ZUtils.qtVersion || "…"
}
}
}
+3
View File
@@ -12,6 +12,9 @@ Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(QString version READ version CONSTANT)
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
public:
// clang-format off
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path);