mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 15:32:50 -05:00
Use proc helper in more places
This commit is contained in:
168
Common/Theme.qml
168
Common/Theme.qml
@@ -82,7 +82,46 @@ Singleton {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Quickshell.execDetached(["mkdir", "-p", stateDir])
|
Quickshell.execDetached(["mkdir", "-p", stateDir])
|
||||||
matugenCheck.running = true
|
Proc.runCommand("matugenCheck", ["which", "matugen"], (output, code) => {
|
||||||
|
matugenAvailable = (code === 0) && !envDisableMatugen
|
||||||
|
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
||||||
|
|
||||||
|
if (!matugenAvailable || isGreeterMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||||
|
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
|
||||||
|
|
||||||
|
if (currentTheme === dynamic) {
|
||||||
|
if (wallpaperPath) {
|
||||||
|
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||||
|
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||||
|
if (wallpaperPath.startsWith("#")) {
|
||||||
|
setDesiredTheme("hex", wallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||||
|
} else {
|
||||||
|
setDesiredTheme("image", wallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let primaryColor
|
||||||
|
let matugenType
|
||||||
|
if (currentTheme === "custom") {
|
||||||
|
if (customThemeData && customThemeData.primary) {
|
||||||
|
primaryColor = customThemeData.primary
|
||||||
|
matugenType = customThemeData.matugen_type
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
primaryColor = currentThemeData.primary
|
||||||
|
matugenType = currentThemeData.matugen_type
|
||||||
|
}
|
||||||
|
|
||||||
|
if (primaryColor) {
|
||||||
|
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||||
|
setDesiredTheme("hex", primaryColor, isLight, iconTheme, matugenType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
if (typeof SessionData !== "undefined") {
|
if (typeof SessionData !== "undefined") {
|
||||||
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
|
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
|
||||||
}
|
}
|
||||||
@@ -669,8 +708,17 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "true" : "false"
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "true" : "false"
|
||||||
gtkApplier.command = [shellDir + "/scripts/gtk.sh", configDir, isLight, shellDir]
|
Proc.runCommand("gtkApplier", [shellDir + "/scripts/gtk.sh", configDir, isLight, shellDir], (output, exitCode) => {
|
||||||
gtkApplier.running = true
|
if (exitCode === 0) {
|
||||||
|
if (typeof ToastService !== "undefined" && typeof NiriService !== "undefined" && !NiriService.matugenSuppression) {
|
||||||
|
ToastService.showInfo("GTK colors applied successfully")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof ToastService !== "undefined") {
|
||||||
|
ToastService.showError("Failed to apply GTK colors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyQtColors() {
|
function applyQtColors() {
|
||||||
@@ -681,8 +729,17 @@ Singleton {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
qtApplier.command = [shellDir + "/scripts/qt.sh", configDir]
|
Proc.runCommand("qtApplier", [shellDir + "/scripts/qt.sh", configDir], (output, exitCode) => {
|
||||||
qtApplier.running = true
|
if (exitCode === 0) {
|
||||||
|
if (typeof ToastService !== "undefined") {
|
||||||
|
ToastService.showInfo("Qt colors applied successfully")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof ToastService !== "undefined") {
|
||||||
|
ToastService.showError("Failed to apply Qt colors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
|
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
|
||||||
@@ -750,57 +807,6 @@ Singleton {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: matugenCheck
|
|
||||||
command: ["which", "matugen"]
|
|
||||||
onExited: code => {
|
|
||||||
matugenAvailable = (code === 0) && !envDisableMatugen
|
|
||||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
|
||||||
|
|
||||||
if (!matugenAvailable || isGreeterMode) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode)
|
|
||||||
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
|
|
||||||
|
|
||||||
if (currentTheme === dynamic) {
|
|
||||||
if (wallpaperPath) {
|
|
||||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
|
||||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
|
||||||
if (wallpaperPath.startsWith("#")) {
|
|
||||||
setDesiredTheme("hex", wallpaperPath, isLight, iconTheme, selectedMatugenType)
|
|
||||||
} else {
|
|
||||||
setDesiredTheme("image", wallpaperPath, isLight, iconTheme, selectedMatugenType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let primaryColor
|
|
||||||
let matugenType
|
|
||||||
if (currentTheme === "custom") {
|
|
||||||
if (customThemeData && customThemeData.primary) {
|
|
||||||
primaryColor = customThemeData.primary
|
|
||||||
matugenType = customThemeData.matugen_type
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
primaryColor = currentThemeData.primary
|
|
||||||
matugenType = currentThemeData.matugen_type
|
|
||||||
}
|
|
||||||
|
|
||||||
if (primaryColor) {
|
|
||||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
|
||||||
setDesiredTheme("hex", primaryColor, isLight, iconTheme, matugenType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: ensureStateDir
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: systemThemeGenerator
|
id: systemThemeGenerator
|
||||||
running: false
|
running: false
|
||||||
@@ -817,56 +823,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: gtkApplier
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: gtkStdout
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr: StdioCollector {
|
|
||||||
id: gtkStderr
|
|
||||||
}
|
|
||||||
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode === 0) {
|
|
||||||
if (typeof ToastService !== "undefined" && typeof NiriService !== "undefined" && !NiriService.matugenSuppression) {
|
|
||||||
ToastService.showInfo("GTK colors applied successfully")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (typeof ToastService !== "undefined") {
|
|
||||||
ToastService.showError("Failed to apply GTK colors: " + gtkStderr.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: qtApplier
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: qtStdout
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr: StdioCollector {
|
|
||||||
id: qtStderr
|
|
||||||
}
|
|
||||||
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode === 0) {
|
|
||||||
if (typeof ToastService !== "undefined") {
|
|
||||||
ToastService.showInfo("Qt colors applied successfully")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (typeof ToastService !== "undefined") {
|
|
||||||
ToastService.showError("Failed to apply Qt colors: " + qtStderr.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: customThemeFileView
|
id: customThemeFileView
|
||||||
watchChanges: currentTheme === "custom"
|
watchChanges: currentTheme === "custom"
|
||||||
|
|||||||
@@ -66,7 +66,13 @@ Item {
|
|||||||
property bool initialized: false
|
property bool initialized: false
|
||||||
|
|
||||||
sourceComponent: DankBar {
|
sourceComponent: DankBar {
|
||||||
onColorPickerRequested: colorPickerModal.show()
|
onColorPickerRequested: {
|
||||||
|
if (colorPickerModal.shouldBeVisible) {
|
||||||
|
colorPickerModal.close()
|
||||||
|
} else {
|
||||||
|
colorPickerModal.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|||||||
@@ -2,17 +2,16 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Wayland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
DankModal {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string pickerTitle: "Choose Color"
|
property string pickerTitle: "Choose Color"
|
||||||
property color selectedColor: Theme.primary
|
property color selectedColor: SessionData.recentColors.length > 0 ? SessionData.recentColors[0] : Theme.primary
|
||||||
property bool shouldBeVisible: false
|
|
||||||
property var onColorSelectedCallback: null
|
property var onColorSelectedCallback: null
|
||||||
|
|
||||||
signal colorSelected(color selectedColor)
|
signal colorSelected(color selectedColor)
|
||||||
@@ -25,23 +24,24 @@ PanelWindow {
|
|||||||
property real gradientX: 0
|
property real gradientX: 0
|
||||||
property real gradientY: 0
|
property real gradientY: 0
|
||||||
|
|
||||||
function open() {
|
readonly property var standardColors: [
|
||||||
currentColor = selectedColor
|
"#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4",
|
||||||
updateFromColor(currentColor)
|
"#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722",
|
||||||
shouldBeVisible = true
|
"#d32f2f", "#c2185b", "#7b1fa2", "#512da8", "#303f9f", "#1976d2", "#0288d1", "#0097a7",
|
||||||
Qt.callLater(() => colorContent.forceActiveFocus())
|
"#00796b", "#388e3c", "#689f38", "#afb42b", "#fbc02d", "#ffa000", "#f57c00", "#e64a19",
|
||||||
}
|
"#c62828", "#ad1457", "#6a1b9a", "#4527a0", "#283593", "#1565c0", "#0277bd", "#00838f",
|
||||||
|
"#00695c", "#2e7d32", "#558b2f", "#9e9d24", "#f9a825", "#ff8f00", "#ef6c00", "#d84315",
|
||||||
function close() {
|
"#ffffff", "#9e9e9e", "#212121"
|
||||||
shouldBeVisible = false
|
]
|
||||||
onColorSelectedCallback = null
|
|
||||||
}
|
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
|
currentColor = selectedColor
|
||||||
|
updateFromColor(currentColor)
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
onColorSelectedCallback = null
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,96 +74,50 @@ PanelWindow {
|
|||||||
saturation = Math.max(0, Math.min(1, x))
|
saturation = Math.max(0, Math.min(1, x))
|
||||||
value = Math.max(0, Math.min(1, 1 - y))
|
value = Math.max(0, Math.min(1, 1 - y))
|
||||||
updateColor()
|
updateColor()
|
||||||
|
selectedColor = currentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickColorFromScreen() {
|
function pickColorFromScreen() {
|
||||||
close()
|
hide()
|
||||||
hyprpickerProcess.running = true
|
Proc.runCommand("hyprpicker", ["hyprpicker", "--format=hex"], (output, errorCode) => {
|
||||||
}
|
if (errorCode !== 0) {
|
||||||
|
console.warn("hyprpicker exited with code:", errorCode)
|
||||||
Process {
|
root.show()
|
||||||
id: hyprpickerProcess
|
return
|
||||||
running: false
|
|
||||||
command: ["hyprpicker", "--format=hex"]
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: data => {
|
|
||||||
const colorStr = data.trim()
|
|
||||||
if (colorStr.length >= 7 && colorStr.startsWith('#')) {
|
|
||||||
root.currentColor = colorStr
|
|
||||||
root.updateFromColor(root.currentColor)
|
|
||||||
hexInput.text = root.currentColor.toString()
|
|
||||||
copyColorToClipboard(colorStr)
|
|
||||||
root.open()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
const colorStr = output.trim()
|
||||||
|
if (colorStr.length >= 7 && colorStr.startsWith('#')) {
|
||||||
onExited: (exitCode, exitStatus) => {
|
const pickedColor = Qt.color(colorStr)
|
||||||
if (exitCode !== 0) {
|
root.selectedColor = pickedColor
|
||||||
console.warn("hyprpicker exited with code:", exitCode)
|
root.currentColor = pickedColor
|
||||||
|
root.updateFromColor(pickedColor)
|
||||||
|
copyColorToClipboard(colorStr)
|
||||||
|
root.show()
|
||||||
}
|
}
|
||||||
root.open()
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var standardColors: [
|
width: 680
|
||||||
"#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4",
|
height: 680
|
||||||
"#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722",
|
backgroundColor: Theme.surfaceContainer
|
||||||
"#d32f2f", "#c2185b", "#7b1fa2", "#512da8", "#303f9f", "#1976d2", "#0288d1", "#0097a7",
|
cornerRadius: Theme.cornerRadius
|
||||||
"#00796b", "#388e3c", "#689f38", "#afb42b", "#fbc02d", "#ffa000", "#f57c00", "#e64a19",
|
borderColor: Theme.outlineMedium
|
||||||
"#c62828", "#ad1457", "#6a1b9a", "#4527a0", "#283593", "#1565c0", "#0277bd", "#00838f",
|
borderWidth: 1
|
||||||
"#00695c", "#2e7d32", "#558b2f", "#9e9d24", "#f9a825", "#ff8f00", "#ef6c00", "#d84315",
|
keepContentLoaded: true
|
||||||
"#ffffff", "#9e9e9e", "#212121"
|
|
||||||
]
|
|
||||||
|
|
||||||
visible: shouldBeVisible
|
onBackgroundClicked: hide()
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:color-picker"
|
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
|
||||||
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: true
|
|
||||||
left: true
|
|
||||||
right: true
|
|
||||||
bottom: true
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: root.close()
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: "#80000000"
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 680
|
|
||||||
height: 680
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
border.color: Theme.outlineMedium
|
|
||||||
border.width: 1
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {} // Prevent clicks from propagating to background
|
|
||||||
}
|
|
||||||
|
|
||||||
|
content: Component {
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: colorContent
|
id: colorContent
|
||||||
|
|
||||||
|
property alias hexInput: hexInput
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: root.shouldBeVisible
|
focus: true
|
||||||
|
|
||||||
Keys.onEscapePressed: event => {
|
Keys.onEscapePressed: event => {
|
||||||
root.close()
|
root.hide()
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +153,7 @@ PanelWindow {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
onClicked: () => {
|
onClicked: () => {
|
||||||
pickColorFromScreen()
|
root.pickColorFromScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +162,7 @@ PanelWindow {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
onClicked: () => {
|
onClicked: () => {
|
||||||
root.close()
|
root.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,12 +283,14 @@ PanelWindow {
|
|||||||
const h = Math.max(0, Math.min(1, mouse.y / height))
|
const h = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
root.hue = h
|
root.hue = h
|
||||||
root.updateColor()
|
root.updateColor()
|
||||||
|
root.selectedColor = root.currentColor
|
||||||
}
|
}
|
||||||
onPositionChanged: mouse => {
|
onPositionChanged: mouse => {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
const h = Math.max(0, Math.min(1, mouse.y / height))
|
const h = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
root.hue = h
|
root.hue = h
|
||||||
root.updateColor()
|
root.updateColor()
|
||||||
|
root.selectedColor = root.currentColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,8 +329,10 @@ PanelWindow {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: () => {
|
onClicked: () => {
|
||||||
root.currentColor = modelData
|
const pickedColor = Qt.color(modelData)
|
||||||
root.updateFromColor(root.currentColor)
|
root.selectedColor = pickedColor
|
||||||
|
root.currentColor = pickedColor
|
||||||
|
root.updateFromColor(pickedColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,8 +387,10 @@ PanelWindow {
|
|||||||
enabled: index < SessionData.recentColors.length
|
enabled: index < SessionData.recentColors.length
|
||||||
onClicked: () => {
|
onClicked: () => {
|
||||||
if (index < SessionData.recentColors.length) {
|
if (index < SessionData.recentColors.length) {
|
||||||
root.currentColor = SessionData.recentColors[index]
|
const pickedColor = SessionData.recentColors[index]
|
||||||
root.updateFromColor(root.currentColor)
|
root.selectedColor = pickedColor
|
||||||
|
root.currentColor = pickedColor
|
||||||
|
root.updateFromColor(pickedColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,6 +419,7 @@ PanelWindow {
|
|||||||
onSliderValueChanged: (newValue) => {
|
onSliderValueChanged: (newValue) => {
|
||||||
root.alpha = newValue / 100
|
root.alpha = newValue / 100
|
||||||
root.updateColor()
|
root.updateColor()
|
||||||
|
root.selectedColor = root.currentColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,6 +470,7 @@ PanelWindow {
|
|||||||
if (!hexPattern.test(text)) return
|
if (!hexPattern.test(text)) return
|
||||||
const color = Qt.color(text)
|
const color = Qt.color(text)
|
||||||
if (color) {
|
if (color) {
|
||||||
|
root.selectedColor = color
|
||||||
root.currentColor = color
|
root.currentColor = color
|
||||||
root.updateFromColor(color)
|
root.updateFromColor(color)
|
||||||
}
|
}
|
||||||
@@ -530,9 +492,9 @@ PanelWindow {
|
|||||||
root.currentColor = color
|
root.currentColor = color
|
||||||
root.updateFromColor(color)
|
root.updateFromColor(color)
|
||||||
root.selectedColor = root.currentColor
|
root.selectedColor = root.currentColor
|
||||||
colorSelected(root.currentColor)
|
root.colorSelected(root.currentColor)
|
||||||
SessionData.addRecentColor(root.currentColor)
|
SessionData.addRecentColor(root.currentColor)
|
||||||
root.close()
|
root.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -549,8 +511,8 @@ PanelWindow {
|
|||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onClicked: root.close()
|
onClicked: root.hide()
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
@@ -570,7 +532,7 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const colorString = root.currentColor.toString()
|
const colorString = root.currentColor.toString()
|
||||||
copyColorToClipboard(colorString)
|
root.copyColorToClipboard(colorString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,4 +123,4 @@ Rectangle {
|
|||||||
toggleBatteryPopup();
|
toggleBatteryPopup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,29 +98,6 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: hyprlandLayoutProcess
|
|
||||||
running: false
|
|
||||||
command: ["hyprctl", "-j", "devices"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(text)
|
|
||||||
// Find the main keyboard and get its active keymap
|
|
||||||
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
|
|
||||||
root.hyprlandKeyboard = mainKeyboard.name
|
|
||||||
if (mainKeyboard && mainKeyboard.active_keymap) {
|
|
||||||
root.currentLayout = mainKeyboard.active_keymap
|
|
||||||
} else {
|
|
||||||
root.currentLayout = "Unknown"
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
root.currentLayout = "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: updateTimer
|
id: updateTimer
|
||||||
interval: 1000
|
interval: 1000
|
||||||
@@ -139,7 +116,24 @@ Rectangle {
|
|||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
root.currentLayout = NiriService.getCurrentKeyboardLayoutName()
|
root.currentLayout = NiriService.getCurrentKeyboardLayoutName()
|
||||||
} else if (CompositorService.isHyprland) {
|
} else if (CompositorService.isHyprland) {
|
||||||
hyprlandLayoutProcess.running = true
|
Proc.runCommand("hyprlandLayout", ["hyprctl", "-j", "devices"], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.currentLayout = "Unknown"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(output)
|
||||||
|
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
|
||||||
|
root.hyprlandKeyboard = mainKeyboard.name
|
||||||
|
if (mainKeyboard && mainKeyboard.active_keymap) {
|
||||||
|
root.currentLayout = mainKeyboard.active_keymap
|
||||||
|
} else {
|
||||||
|
root.currentLayout = "Unknown"
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
root.currentLayout = "Unknown"
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ Column {
|
|||||||
// Match count display
|
// Match count display
|
||||||
StyledText {
|
StyledText {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
text: matchCount > 0 ? I18n.tr("%1/%2").arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? I18n.tr("No matches") : ""
|
text: matchCount > 0 ? "%1/%2".arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? I18n.tr("No matches") : ""
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: matchCount > 0 ? Theme.primary : Theme.surfaceTextMedium
|
color: matchCount > 0 ? Theme.primary : Theme.surfaceTextMedium
|
||||||
visible: searchQuery.length > 0
|
visible: searchQuery.length > 0
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -160,7 +160,20 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (niriSocket && niriSocket.length > 0) {
|
if (niriSocket && niriSocket.length > 0) {
|
||||||
niriSocketCheck.running = true
|
Proc.runCommand("niriSocketCheck", ["test", "-S", root.niriSocket], (output, exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
root.isNiri = true
|
||||||
|
root.isHyprland = false
|
||||||
|
root.compositor = "niri"
|
||||||
|
console.log("CompositorService: Detected Niri with socket:", root.niriSocket)
|
||||||
|
NiriService.generateNiriBinds()
|
||||||
|
} else {
|
||||||
|
root.isHyprland = false
|
||||||
|
root.isNiri = true
|
||||||
|
root.compositor = "niri"
|
||||||
|
console.warn("CompositorService: Niri socket check failed, defaulting to Niri anyway")
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
} else {
|
} else {
|
||||||
isHyprland = false
|
isHyprland = false
|
||||||
isNiri = false
|
isNiri = false
|
||||||
@@ -188,24 +201,4 @@ Singleton {
|
|||||||
}
|
}
|
||||||
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
|
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: niriSocketCheck
|
|
||||||
command: ["test", "-S", root.niriSocket]
|
|
||||||
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode === 0) {
|
|
||||||
root.isNiri = true
|
|
||||||
root.isHyprland = false
|
|
||||||
root.compositor = "niri"
|
|
||||||
console.log("CompositorService: Detected Niri with socket:", root.niriSocket)
|
|
||||||
NiriService.generateNiriBinds()
|
|
||||||
} else {
|
|
||||||
root.isHyprland = false
|
|
||||||
root.isNiri = true
|
|
||||||
root.compositor = "niri"
|
|
||||||
console.warn("CompositorService: Niri socket check failed, defaulting to Niri anyway")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import qs.Common
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -18,11 +18,62 @@ Singleton {
|
|||||||
property bool profileAvailable: false
|
property bool profileAvailable: false
|
||||||
|
|
||||||
function getUserInfo() {
|
function getUserInfo() {
|
||||||
userInfoProcess.running = true
|
Proc.runCommand("userInfo", ["bash", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.username = "User"
|
||||||
|
root.fullName = "User"
|
||||||
|
root.hostname = "System"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parts = output.trim().split("|")
|
||||||
|
if (parts.length >= 3) {
|
||||||
|
root.username = parts[0] || ""
|
||||||
|
root.fullName = parts[1] || parts[0] || ""
|
||||||
|
root.hostname = parts[2] || ""
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUptime() {
|
function getUptime() {
|
||||||
uptimeProcess.running = true
|
Proc.runCommand("uptime", ["cat", "/proc/uptime"], (output, exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.uptime = "Unknown"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const seconds = parseInt(output.split(" ")[0])
|
||||||
|
const days = Math.floor(seconds / 86400)
|
||||||
|
const hours = Math.floor((seconds % 86400) / 3600)
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60)
|
||||||
|
|
||||||
|
const parts = []
|
||||||
|
if (days > 0) {
|
||||||
|
parts.push(`${days} day${days === 1 ? "" : "s"}`)
|
||||||
|
}
|
||||||
|
if (hours > 0) {
|
||||||
|
parts.push(`${hours} hour${hours === 1 ? "" : "s"}`)
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.length > 0) {
|
||||||
|
root.uptime = `up ${parts.join(", ")}`
|
||||||
|
} else {
|
||||||
|
root.uptime = `up ${seconds} seconds`
|
||||||
|
}
|
||||||
|
|
||||||
|
let shortUptime = "up"
|
||||||
|
if (days > 0) {
|
||||||
|
shortUptime += ` ${days}d`
|
||||||
|
}
|
||||||
|
if (hours > 0) {
|
||||||
|
shortUptime += ` ${hours}h`
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
shortUptime += ` ${minutes}m`
|
||||||
|
}
|
||||||
|
root.shortUptime = shortUptime
|
||||||
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshUserInfo() {
|
function refreshUserInfo() {
|
||||||
@@ -34,82 +85,4 @@ Singleton {
|
|||||||
getUserInfo()
|
getUserInfo()
|
||||||
getUptime()
|
getUptime()
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: userInfoProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""]
|
|
||||||
running: false
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
|
|
||||||
root.username = "User"
|
|
||||||
root.fullName = "User"
|
|
||||||
root.hostname = "System"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const parts = text.trim().split("|")
|
|
||||||
if (parts.length >= 3) {
|
|
||||||
root.username = parts[0] || ""
|
|
||||||
root.fullName = parts[1] || parts[0] || ""
|
|
||||||
root.hostname = parts[2] || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: uptimeProcess
|
|
||||||
|
|
||||||
command: ["cat", "/proc/uptime"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
root.uptime = "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const seconds = parseInt(text.split(" ")[0])
|
|
||||||
const days = Math.floor(seconds / 86400)
|
|
||||||
const hours = Math.floor((seconds % 86400) / 3600)
|
|
||||||
const minutes = Math.floor((seconds % 3600) / 60)
|
|
||||||
|
|
||||||
const parts = []
|
|
||||||
if (days > 0) {
|
|
||||||
parts.push(`${days} day${days === 1 ? "" : "s"}`)
|
|
||||||
}
|
|
||||||
if (hours > 0) {
|
|
||||||
parts.push(`${hours} hour${hours === 1 ? "" : "s"}`)
|
|
||||||
}
|
|
||||||
if (minutes > 0) {
|
|
||||||
parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parts.length > 0) {
|
|
||||||
root.uptime = `up ${parts.join(", ")}`
|
|
||||||
} else {
|
|
||||||
root.uptime = `up ${seconds} seconds`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create short uptime format
|
|
||||||
let shortUptime = "up"
|
|
||||||
if (days > 0) {
|
|
||||||
shortUptime += ` ${days}d`
|
|
||||||
}
|
|
||||||
if (hours > 0) {
|
|
||||||
shortUptime += ` ${hours}h`
|
|
||||||
}
|
|
||||||
if (minutes > 0) {
|
|
||||||
shortUptime += ` ${minutes}m`
|
|
||||||
}
|
|
||||||
root.shortUptime = shortUptime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
@@ -31,8 +30,6 @@ Item {
|
|||||||
function resetSearchState() {
|
function resetSearchState() {
|
||||||
locationSearchTimer.stop()
|
locationSearchTimer.stop()
|
||||||
dropdownHideTimer.stop()
|
dropdownHideTimer.stop()
|
||||||
if (locationSearcher.running)
|
|
||||||
locationSearcher.running = false
|
|
||||||
isLoading = false
|
isLoading = false
|
||||||
searchResultsModel.clear()
|
searchResultsModel.clear()
|
||||||
}
|
}
|
||||||
@@ -52,17 +49,52 @@ Item {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (locationInput.text.length > 2) {
|
if (locationInput.text.length > 2) {
|
||||||
if (locationSearcher.running)
|
|
||||||
locationSearcher.running = false
|
|
||||||
|
|
||||||
searchResultsModel.clear()
|
searchResultsModel.clear()
|
||||||
root.isLoading = true
|
root.isLoading = true
|
||||||
const searchLocation = locationInput.text
|
const searchLocation = locationInput.text
|
||||||
root.currentSearchText = searchLocation
|
root.currentSearchText = searchLocation
|
||||||
const encodedLocation = encodeURIComponent(searchLocation)
|
const encodedLocation = encodeURIComponent(searchLocation)
|
||||||
const curlCommand = `curl -4 -s --connect-timeout 5 --max-time 10 'https://nominatim.openstreetmap.org/search?q=${encodedLocation}&format=json&limit=5&addressdetails=1'`
|
const curlCommand = `curl -4 -s --connect-timeout 5 --max-time 10 'https://nominatim.openstreetmap.org/search?q=${encodedLocation}&format=json&limit=5&addressdetails=1'`
|
||||||
locationSearcher.command = ["bash", "-c", curlCommand]
|
Proc.runCommand("locationSearch", ["bash", "-c", curlCommand], (output, exitCode) => {
|
||||||
locationSearcher.running = true
|
root.isLoading = false
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
searchResultsModel.clear()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (root.currentSearchText !== locationInput.text)
|
||||||
|
return
|
||||||
|
|
||||||
|
const raw = output.trim()
|
||||||
|
searchResultsModel.clear()
|
||||||
|
if (!raw || raw[0] !== "[") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(raw)
|
||||||
|
if (data.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (var i = 0; i < Math.min(data.length, 5); i++) {
|
||||||
|
const location = data[i]
|
||||||
|
if (location.display_name && location.lat && location.lon) {
|
||||||
|
const parts = location.display_name.split(', ')
|
||||||
|
let cleanName = parts[0]
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const state = parts[parts.length - 2]
|
||||||
|
if (state && state !== cleanName)
|
||||||
|
cleanName += `, ${state}`
|
||||||
|
}
|
||||||
|
const query = `${location.lat},${location.lon}`
|
||||||
|
searchResultsModel.append({
|
||||||
|
"name": cleanName,
|
||||||
|
"query": query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,58 +111,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: locationSearcher
|
|
||||||
|
|
||||||
command: ["bash", "-c", "echo"]
|
|
||||||
running: false
|
|
||||||
onExited: exitCode => {
|
|
||||||
root.isLoading = false
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
searchResultsModel.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (root.currentSearchText !== locationInput.text)
|
|
||||||
return
|
|
||||||
|
|
||||||
const raw = text.trim()
|
|
||||||
root.isLoading = false
|
|
||||||
searchResultsModel.clear()
|
|
||||||
if (!raw || raw[0] !== "[") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(raw)
|
|
||||||
if (data.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for (var i = 0; i < Math.min(data.length, 5); i++) {
|
|
||||||
const location = data[i]
|
|
||||||
if (location.display_name && location.lat && location.lon) {
|
|
||||||
const parts = location.display_name.split(', ')
|
|
||||||
let cleanName = parts[0]
|
|
||||||
if (parts.length > 1) {
|
|
||||||
const state = parts[parts.length - 2]
|
|
||||||
if (state && state !== cleanName)
|
|
||||||
cleanName += `, ${state}`
|
|
||||||
}
|
|
||||||
const query = `${location.lat},${location.lon}`
|
|
||||||
searchResultsModel.append({
|
|
||||||
"name": cleanName,
|
|
||||||
"query": query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: searchInputField
|
id: searchInputField
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
|
||||||
@@ -16,19 +15,16 @@ IconImage {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
layer.enabled: hasColorOverride
|
layer.enabled: hasColorOverride
|
||||||
|
|
||||||
Process {
|
Component.onCompleted: {
|
||||||
running: true
|
Proc.runCommand("systemLogo", ["sh", "-c", ". /etc/os-release && echo $LOGO"], (output, exitCode) => {
|
||||||
command: ["sh", "-c", ". /etc/os-release && echo $LOGO"]
|
if (exitCode !== 0) return
|
||||||
|
const logo = output.trim()
|
||||||
stdout: StdioCollector {
|
if (logo === "cachyos") {
|
||||||
onStreamFinished: () => {
|
source = "file:///usr/share/icons/cachyos.svg"
|
||||||
if (text.trim() === "cachyos") {
|
return
|
||||||
source = "file:///usr/share/icons/cachyos.svg"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
source = Quickshell.iconPath(text.trim(), true)
|
|
||||||
}
|
}
|
||||||
}
|
source = Quickshell.iconPath(logo, true)
|
||||||
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
|
|||||||
Reference in New Issue
Block a user