add crypto
This commit is contained in:
parent
90cbe489f6
commit
af6a3bce3e
120 changed files with 24616 additions and 462 deletions
80
modules/home/services/quickshell/qml/Core/Corners.qml
Normal file
80
modules/home/services/quickshell/qml/Core/Corners.qml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import "root:/Data" as Settings
|
||||
|
||||
// Concave corner shape component for rounded panel edges
|
||||
Shape {
|
||||
id: root
|
||||
|
||||
property string position: "topleft" // Corner position: topleft/topright/bottomleft/bottomright
|
||||
property real size: 1.0 // Scale multiplier for entire corner
|
||||
property int concaveWidth: 100 * size
|
||||
property int concaveHeight: 60 * size
|
||||
property int offsetX: -20
|
||||
property int offsetY: -20
|
||||
property color fillColor: Settings.Colors.bgColor
|
||||
property int arcRadius: 20 * size
|
||||
|
||||
// Position flags derived from position string
|
||||
property bool _isTop: position.includes("top")
|
||||
property bool _isLeft: position.includes("left")
|
||||
property bool _isRight: position.includes("right")
|
||||
property bool _isBottom: position.includes("bottom")
|
||||
|
||||
// Base coordinates for left corner shape
|
||||
property real _baseStartX: 30 * size
|
||||
property real _baseStartY: _isTop ? 20 * size : 0
|
||||
property real _baseLineX: 30 * size
|
||||
property real _baseLineY: _isTop ? 0 : 20 * size
|
||||
property real _baseArcX: 50 * size
|
||||
property real _baseArcY: _isTop ? 20 * size : 0
|
||||
|
||||
// Mirror coordinates for right corners
|
||||
property real _startX: _isRight ? (concaveWidth - _baseStartX) : _baseStartX
|
||||
property real _startY: _baseStartY
|
||||
property real _lineX: _isRight ? (concaveWidth - _baseLineX) : _baseLineX
|
||||
property real _lineY: _baseLineY
|
||||
property real _arcX: _isRight ? (concaveWidth - _baseArcX) : _baseArcX
|
||||
property real _arcY: _baseArcY
|
||||
|
||||
// Arc direction varies by corner to maintain proper concave shape
|
||||
property int _arcDirection: {
|
||||
if (_isTop && _isLeft) return PathArc.Counterclockwise
|
||||
if (_isTop && _isRight) return PathArc.Clockwise
|
||||
if (_isBottom && _isLeft) return PathArc.Clockwise
|
||||
if (_isBottom && _isRight) return PathArc.Counterclockwise
|
||||
return PathArc.Counterclockwise
|
||||
}
|
||||
|
||||
width: concaveWidth
|
||||
height: concaveHeight
|
||||
// Position relative to parent based on corner type
|
||||
x: _isLeft ? offsetX : (parent ? parent.width - width + offsetX : 0)
|
||||
y: _isTop ? offsetY : (parent ? parent.height - height + offsetY : 0)
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
layer.enabled: true
|
||||
layer.samples: 4
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 0
|
||||
fillColor: root.fillColor
|
||||
strokeColor: root.fillColor // Use same color as fill to eliminate artifacts
|
||||
|
||||
startX: root._startX
|
||||
startY: root._startY
|
||||
|
||||
PathLine {
|
||||
x: root._lineX
|
||||
y: root._lineY
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: root._arcX
|
||||
y: root._arcY
|
||||
radiusX: root.arcRadius
|
||||
radiusY: root.arcRadius
|
||||
useLargeArc: false
|
||||
direction: root._arcDirection
|
||||
}
|
||||
}
|
||||
}
|
||||
48
modules/home/services/quickshell/qml/Core/LoaderManager.qml
Normal file
48
modules/home/services/quickshell/qml/Core/LoaderManager.qml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
// Keep track of loaded components
|
||||
property var activeLoaders: ({})
|
||||
|
||||
// Dynamically load a QML component
|
||||
function load(componentUrl, parent, properties) {
|
||||
if (!activeLoaders[componentUrl]) {
|
||||
var loader = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
Loader {
|
||||
active: false
|
||||
asynchronous: true
|
||||
visible: false
|
||||
}
|
||||
`, parent);
|
||||
|
||||
loader.source = componentUrl
|
||||
loader.active = true
|
||||
|
||||
if (properties) {
|
||||
for (var prop in properties) {
|
||||
loader[prop] = properties[prop]
|
||||
}
|
||||
}
|
||||
|
||||
activeLoaders[componentUrl] = loader
|
||||
}
|
||||
return activeLoaders[componentUrl]
|
||||
}
|
||||
|
||||
// Destroy and remove a loaded component
|
||||
function unload(componentUrl) {
|
||||
if (activeLoaders[componentUrl]) {
|
||||
activeLoaders[componentUrl].active = false
|
||||
activeLoaders[componentUrl].destroy()
|
||||
delete activeLoaders[componentUrl]
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a component is loaded
|
||||
function isLoaded(componentUrl) {
|
||||
return !!activeLoaders[componentUrl]
|
||||
}
|
||||
}
|
||||
175
modules/home/services/quickshell/qml/Core/ProcessManager.qml
Normal file
175
modules/home/services/quickshell/qml/Core/ProcessManager.qml
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
pragma Singleton
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
// System process and resource monitoring
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
// System resource metrics
|
||||
property real cpuUsage: 0
|
||||
property real ramUsage: 0
|
||||
property real totalRam: 0
|
||||
property real usedRam: 0
|
||||
|
||||
// System control processes
|
||||
property Process shutdownProcess: Process {
|
||||
command: ["shutdown", "-h", "now"]
|
||||
}
|
||||
|
||||
property Process rebootProcess: Process {
|
||||
command: ["reboot"]
|
||||
}
|
||||
|
||||
property Process lockProcess: Process {
|
||||
command: ["hyprlock"]
|
||||
}
|
||||
|
||||
property Process logoutProcess: Process {
|
||||
command: ["loginctl", "terminate-user", "$USER"]
|
||||
}
|
||||
|
||||
property Process pavucontrolProcess: Process {
|
||||
command: ["pavucontrol"]
|
||||
}
|
||||
|
||||
// Resource monitoring processes
|
||||
property Process cpuProcess: Process {
|
||||
command: ["sh", "-c", "grep '^cpu ' /proc/stat | awk '{usage=($2+$3+$4)*100/($2+$3+$4+$5)} END {print usage}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.cpuUsage = parseFloat(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property Process ramProcess: Process {
|
||||
command: ["sh", "-c", "free -b | awk '/Mem:/ {print $2\" \"$3\" \"$3/$2*100}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
var parts = data.trim().split(/\s+/)
|
||||
if (parts.length >= 3) {
|
||||
root.totalRam = parseFloat(parts[0]) / (1024 * 1024 * 1024)
|
||||
root.usedRam = parseFloat(parts[1]) / (1024 * 1024 * 1024)
|
||||
root.ramUsage = parseFloat(parts[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Monitoring timers (start manually when needed)
|
||||
property Timer cpuTimer: Timer {
|
||||
interval: 30000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
cpuProcess.running = false
|
||||
cpuProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
property Timer ramTimer: Timer {
|
||||
interval: 30000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
ramProcess.running = false
|
||||
ramProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
// System control functions
|
||||
function shutdown() {
|
||||
console.log("Executing shutdown command")
|
||||
shutdownProcess.running = true
|
||||
}
|
||||
|
||||
function reboot() {
|
||||
console.log("Executing reboot command")
|
||||
rebootProcess.running = true
|
||||
}
|
||||
|
||||
function lock() {
|
||||
console.log("Executing lock command")
|
||||
lockProcess.running = true
|
||||
}
|
||||
|
||||
function logout() {
|
||||
console.log("Executing logout command")
|
||||
logoutProcess.running = true
|
||||
}
|
||||
|
||||
function openPavuControl() {
|
||||
console.log("Opening PavuControl")
|
||||
pavucontrolProcess.running = true
|
||||
}
|
||||
|
||||
// Performance monitoring control
|
||||
function startMonitoring() {
|
||||
console.log("Starting system monitoring")
|
||||
cpuTimer.running = true
|
||||
ramTimer.running = true
|
||||
}
|
||||
|
||||
function stopMonitoring() {
|
||||
console.log("Stopping system monitoring")
|
||||
cpuTimer.running = false
|
||||
ramTimer.running = false
|
||||
}
|
||||
|
||||
function setMonitoringInterval(intervalMs) {
|
||||
console.log("Setting monitoring interval to", intervalMs, "ms")
|
||||
cpuTimer.interval = intervalMs
|
||||
ramTimer.interval = intervalMs
|
||||
}
|
||||
|
||||
function refreshSystemStats() {
|
||||
console.log("Manually refreshing system stats")
|
||||
cpuProcess.running = false
|
||||
cpuProcess.running = true
|
||||
ramProcess.running = false
|
||||
ramProcess.running = true
|
||||
}
|
||||
|
||||
// Process state queries
|
||||
function isShutdownRunning() { return shutdownProcess.running }
|
||||
function isRebootRunning() { return rebootProcess.running }
|
||||
function isLockRunning() { return lockProcess.running }
|
||||
function isLogoutRunning() { return logoutProcess.running }
|
||||
function isPavuControlRunning() { return pavucontrolProcess.running }
|
||||
function isMonitoringActive() { return cpuTimer.running && ramTimer.running }
|
||||
|
||||
function stopPavuControl() {
|
||||
pavucontrolProcess.running = false
|
||||
}
|
||||
|
||||
// Formatted output helpers
|
||||
function getCpuUsageFormatted() {
|
||||
return Math.round(cpuUsage) + "%"
|
||||
}
|
||||
|
||||
function getRamUsageFormatted() {
|
||||
return Math.round(ramUsage) + "% (" + usedRam.toFixed(1) + "GB/" + totalRam.toFixed(1) + "GB)"
|
||||
}
|
||||
|
||||
function getRamUsageSimple() {
|
||||
return Math.round(ramUsage) + "%"
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
// Stop all timers
|
||||
cpuTimer.running = false
|
||||
ramTimer.running = false
|
||||
|
||||
// Stop monitoring processes
|
||||
cpuProcess.running = false
|
||||
ramProcess.running = false
|
||||
|
||||
// Stop control processes if running
|
||||
if (shutdownProcess.running) shutdownProcess.running = false
|
||||
if (rebootProcess.running) rebootProcess.running = false
|
||||
if (lockProcess.running) lockProcess.running = false
|
||||
if (logoutProcess.running) logoutProcess.running = false
|
||||
if (pavucontrolProcess.running) pavucontrolProcess.running = false
|
||||
}
|
||||
}
|
||||
265
modules/home/services/quickshell/qml/Core/Version.qml
Normal file
265
modules/home/services/quickshell/qml/Core/Version.qml
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "root:/Data" as Data
|
||||
|
||||
// System version watermark display
|
||||
PanelWindow {
|
||||
id: systemVersion
|
||||
|
||||
anchors {
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
margins {
|
||||
right: 60
|
||||
bottom: 60
|
||||
}
|
||||
visible: false
|
||||
|
||||
implicitWidth: systemInfoContent.width
|
||||
implicitHeight: systemInfoContent.height
|
||||
|
||||
color: "transparent"
|
||||
|
||||
mask: Region {}
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
WlrLayershell.exclusiveZone: 0
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
WlrLayershell.namespace: "quickshell-version"
|
||||
|
||||
Timer {
|
||||
id: startupTimer
|
||||
interval: 1500
|
||||
running: true
|
||||
onTriggered: {
|
||||
visible = true
|
||||
}
|
||||
}
|
||||
|
||||
component Details: QtObject {
|
||||
property string version
|
||||
property string commit
|
||||
}
|
||||
|
||||
property QtObject os: QtObject {
|
||||
property string name: "Loading..."
|
||||
property Details details: Details {
|
||||
property string generation: "?"
|
||||
}
|
||||
}
|
||||
|
||||
property QtObject wm: QtObject {
|
||||
property string name: "Loading..."
|
||||
property Details details: Details {}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
osFile.reload();
|
||||
genProcess.running = true;
|
||||
wmProcess.running = true;
|
||||
niriProcess.running = true;
|
||||
}
|
||||
|
||||
// Periodic refresh disabled - version info rarely changes
|
||||
Timer {
|
||||
running: false
|
||||
interval: 300000
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
osFile.reload();
|
||||
genProcess.running = true;
|
||||
wmProcess.running = true;
|
||||
niriProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse OS info from /etc/os-release
|
||||
FileView {
|
||||
id: osFile
|
||||
path: "/etc/os-release"
|
||||
|
||||
onLoaded: {
|
||||
const data = text().trim().split("\n");
|
||||
|
||||
const nameLine = data.find((str) => str.match(/^NAME=/));
|
||||
const versionLine = data.find((str) => str.match(/^VERSION_ID=/));
|
||||
const buildLine = data.find((str) => str.match(/^BUILD_ID=/));
|
||||
|
||||
if (nameLine) {
|
||||
systemVersion.os.name = nameLine.split("=")[1].replace(/"/g, "");
|
||||
}
|
||||
if (versionLine) {
|
||||
systemVersion.os.details.version = versionLine.split("=")[1].replace(/"/g, "");
|
||||
}
|
||||
if (buildLine) {
|
||||
const commit = buildLine.split("=")[1].split(".")[3];
|
||||
if (commit) {
|
||||
systemVersion.os.details.commit = commit.replace(/"/g, "").toUpperCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get NixOS generation number
|
||||
Process {
|
||||
id: genProcess
|
||||
running: true
|
||||
command: ["sh", "-c", "nixos-rebuild list-generations"]
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: (data) => {
|
||||
const line = data.trim().split("\n").find((str) => str.match(/current/));
|
||||
if (line) {
|
||||
const current = line.split(" ")[0];
|
||||
systemVersion.os.details.generation = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Detect desktop environment
|
||||
Process {
|
||||
id: wmProcess
|
||||
running: true
|
||||
command: ["sh", "-c", "echo $XDG_CURRENT_DESKTOP"]
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: (data) => {
|
||||
const result = data.trim();
|
||||
if (result && result !== "") {
|
||||
systemVersion.wm.name = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Niri compositor version
|
||||
Process {
|
||||
id: niriProcess
|
||||
running: true
|
||||
command: ["sh", "-c", "niri msg version"]
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: (data) => {
|
||||
const output = data.trim();
|
||||
|
||||
const compositorMatch = output.match(/Compositor version: (\S+)/);
|
||||
if (compositorMatch && compositorMatch[1]) {
|
||||
systemVersion.wm.details.version = compositorMatch[1];
|
||||
}
|
||||
|
||||
const commitMatch = output.match(/\((\S+)\)/);
|
||||
if (commitMatch && commitMatch[1]) {
|
||||
systemVersion.wm.details.commit = commitMatch[1].toUpperCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// macOS-inspired typography layout
|
||||
ColumnLayout {
|
||||
id: systemInfoContent
|
||||
spacing: 6
|
||||
|
||||
RowLayout {
|
||||
spacing: 16
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
// OS information
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Text {
|
||||
text: systemVersion.os.name
|
||||
color: (Data.ThemeManager.currentTheme && Data.ThemeManager.currentTheme.type === "dark") ? "#40ffffff" : "#40000000"
|
||||
font.family: "SF Pro Display, -apple-system, system-ui, sans-serif"
|
||||
font.pointSize: 16
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: -0.4
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Text {
|
||||
text: {
|
||||
let details = [];
|
||||
if (systemVersion.os.details.version) {
|
||||
details.push(systemVersion.os.details.version);
|
||||
}
|
||||
if (systemVersion.os.details.commit) {
|
||||
details.push("(" + systemVersion.os.details.commit + ")");
|
||||
}
|
||||
if (systemVersion.os.details.generation && systemVersion.os.details.generation !== "?") {
|
||||
details.push("Gen " + systemVersion.os.details.generation);
|
||||
}
|
||||
return details.join(" ");
|
||||
}
|
||||
color: (Data.ThemeManager.currentTheme && Data.ThemeManager.currentTheme.type === "dark") ? "#30ffffff" : "#30000000"
|
||||
font.family: "SF Mono, Consolas, Monaco, monospace"
|
||||
font.pointSize: 10
|
||||
font.weight: Font.Medium
|
||||
visible: text.length > 0
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "│"
|
||||
color: (Data.ThemeManager.currentTheme && Data.ThemeManager.currentTheme.type === "dark") ? "#20ffffff" : "#20000000"
|
||||
font.family: "SF Pro Display, -apple-system, system-ui, sans-serif"
|
||||
font.pointSize: 14
|
||||
font.weight: Font.Light
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
// Window manager information
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Text {
|
||||
text: systemVersion.wm.name
|
||||
color: (Data.ThemeManager.currentTheme && Data.ThemeManager.currentTheme.type === "dark") ? "#40ffffff" : "#40000000"
|
||||
font.family: "SF Pro Display, -apple-system, system-ui, sans-serif"
|
||||
font.pointSize: 16
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: -0.4
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Text {
|
||||
text: {
|
||||
let details = [];
|
||||
if (systemVersion.wm.details.version) {
|
||||
details.push(systemVersion.wm.details.version);
|
||||
}
|
||||
if (systemVersion.wm.details.commit) {
|
||||
details.push("(" + systemVersion.wm.details.commit + ")");
|
||||
}
|
||||
return details.join(" ");
|
||||
}
|
||||
color: (Data.ThemeManager.currentTheme && Data.ThemeManager.currentTheme.type === "dark") ? "#30ffffff" : "#30000000"
|
||||
font.family: "SF Mono, Consolas, Monaco, monospace"
|
||||
font.pointSize: 10
|
||||
font.weight: Font.Medium
|
||||
visible: text.length > 0
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (genProcess.running) genProcess.running = false
|
||||
if (wmProcess.running) wmProcess.running = false
|
||||
if (niriProcess.running) niriProcess.running = false
|
||||
}
|
||||
}
|
||||
47
modules/home/services/quickshell/qml/Core/Wallpaper.qml
Normal file
47
modules/home/services/quickshell/qml/Core/Wallpaper.qml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "root:/Data" as Data
|
||||
|
||||
// Wallpaper background layer
|
||||
PanelWindow {
|
||||
id: wallpaperWindow
|
||||
required property var screen
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
margins.top: 0
|
||||
margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
exclusiveZone: 0
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
WlrLayershell.namespace: "quickshell-wallpaper"
|
||||
color: "transparent"
|
||||
visible: true
|
||||
|
||||
Image {
|
||||
id: wallpaperImage
|
||||
anchors.fill: parent
|
||||
source: Data.WallpaperManager.currentWallpaper
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false // Reduce memory usage
|
||||
visible: true
|
||||
|
||||
// Fallback when wallpaper fails to load
|
||||
Rectangle {
|
||||
id: fallbackBackground
|
||||
anchors.fill: parent
|
||||
color: Data.ThemeManager.bgColor
|
||||
visible: wallpaperImage.status !== Image.Ready || !wallpaperImage.source
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue