Cleaned up ColorSchemeTab, added program checks, added firefox template
Matugen: added firefox (pywalfox) template SidePanelToggle: use ProgramCheckerService for gpu-screen-recorder ColorSchemeTab: use NCollapsible for matugen templates, use ProgramCheckerService to detect available programs (for matugen templates) NCollapsible: create collapsible category
This commit is contained in:
parent
c0d6780c3d
commit
fa838ecdb1
8 changed files with 514 additions and 148 deletions
|
|
@ -70,6 +70,12 @@ Singleton {
|
||||||
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/vesktop.css"')
|
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/vesktop.css"')
|
||||||
lines.push('output_path = "~/.config/vesktop/themes/noctalia.theme.css"')
|
lines.push('output_path = "~/.config/vesktop/themes/noctalia.theme.css"')
|
||||||
}
|
}
|
||||||
|
if (Settings.data.matugen.pywalfox) {
|
||||||
|
lines.push("\n[templates.pywalfox]")
|
||||||
|
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/pywalfox.json"')
|
||||||
|
lines.push('output_path = "~/.cache/wal/colors.json"')
|
||||||
|
lines.push('post_hook = "pywalfox update"')
|
||||||
|
}
|
||||||
|
|
||||||
return lines.join("\n") + "\n"
|
return lines.join("\n") + "\n"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
Assets/Matugen/templates/pywalfox.json
Normal file
22
Assets/Matugen/templates/pywalfox.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"wallpaper": "{{image}}",
|
||||||
|
"alpha": "100",
|
||||||
|
"colors": {
|
||||||
|
"color0": "{{colors.background.default.hex}}",
|
||||||
|
"color1": "",
|
||||||
|
"color2": "",
|
||||||
|
"color3": "",
|
||||||
|
"color4": "",
|
||||||
|
"color5": "",
|
||||||
|
"color6": "",
|
||||||
|
"color7": "",
|
||||||
|
"color8": "",
|
||||||
|
"color9": "",
|
||||||
|
"color10": "{{colors.primary.default.hex}}",
|
||||||
|
"color11": "",
|
||||||
|
"color12": "",
|
||||||
|
"color13": "{{colors.surface_bright.default.hex}}",
|
||||||
|
"color14": "",
|
||||||
|
"color15": "{{colors.on_surface.default.hex}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -449,6 +449,7 @@ Singleton {
|
||||||
property bool foot: false
|
property bool foot: false
|
||||||
property bool fuzzel: false
|
property bool fuzzel: false
|
||||||
property bool vesktop: false
|
property bool vesktop: false
|
||||||
|
property bool pywalfox: false
|
||||||
property bool enableUserTemplates: false
|
property bool enableUserTemplates: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ NIconButton {
|
||||||
colorFg: Color.mOnSurface
|
colorFg: Color.mOnSurface
|
||||||
colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary
|
colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary
|
||||||
colorBorder: Color.transparent
|
colorBorder: Color.transparent
|
||||||
colorBorderHover: useDistroLogo ? Color.mTertiary : Color.transparent
|
colorBorderHover: useDistroLogo ? Color.mTertiary : Color.transparent
|
||||||
onClicked: PanelService.getPanel("sidePanel")?.toggle(this)
|
onClicked: PanelService.getPanel("sidePanel")?.toggle(this)
|
||||||
onRightClicked: PanelService.getPanel("settingsPanel")?.toggle()
|
onRightClicked: PanelService.getPanel("settingsPanel")?.toggle()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -318,146 +318,187 @@ ColumnLayout {
|
||||||
visible: Settings.data.colorSchemes.useWallpaperColors
|
visible: Settings.data.colorSchemes.useWallpaperColors
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matugen template toggles (moved from MatugenTab)
|
// Matugen template toggles organized by category
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: Style.marginL * scaling
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: Settings.data.colorSchemes.useWallpaperColors
|
visible: Settings.data.colorSchemes.useWallpaperColors
|
||||||
|
spacing: Style.marginL * scaling
|
||||||
|
|
||||||
ColumnLayout {
|
// UI Components
|
||||||
spacing: Style.marginS * scaling
|
NCollapsible {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
label: "UI"
|
||||||
|
description: "Desktop environment and UI toolkit theming."
|
||||||
|
defaultExpanded: false
|
||||||
|
|
||||||
NText {
|
NCheckbox {
|
||||||
text: "Matugen Templates"
|
label: "GTK 4 (libadwaita)"
|
||||||
font.pointSize: Style.fontSizeXXL * scaling
|
description: "Write ~/.config/gtk-4.0/gtk.css"
|
||||||
font.weight: Style.fontWeightBold
|
checked: Settings.data.matugen.gtk4
|
||||||
color: Color.mSecondary
|
onToggled: checked => {
|
||||||
|
Settings.data.matugen.gtk4 = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NText {
|
NCheckbox {
|
||||||
text: "Select which external components Matugen should apply theming to."
|
label: "GTK 3"
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
description: "Write ~/.config/gtk-3.0/gtk.css"
|
||||||
color: Color.mOnSurfaceVariant
|
checked: Settings.data.matugen.gtk3
|
||||||
Layout.fillWidth: true
|
onToggled: checked => {
|
||||||
wrapMode: Text.WordWrap
|
Settings.data.matugen.gtk3 = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Qt6ct"
|
||||||
|
description: "Write ~/.config/qt6ct/colors/noctalia.conf"
|
||||||
|
checked: Settings.data.matugen.qt6
|
||||||
|
onToggled: checked => {
|
||||||
|
Settings.data.matugen.qt6 = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Qt5ct"
|
||||||
|
description: "Write ~/.config/qt5ct/colors/noctalia.conf"
|
||||||
|
checked: Settings.data.matugen.qt5
|
||||||
|
onToggled: checked => {
|
||||||
|
Settings.data.matugen.qt5 = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NCheckbox {
|
// Terminal Emulators
|
||||||
label: "GTK 4 (libadwaita)"
|
NCollapsible {
|
||||||
description: "Write ~/.config/gtk-4.0/gtk.css"
|
|
||||||
checked: Settings.data.matugen.gtk4
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.gtk4 = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "GTK 3"
|
|
||||||
description: "Write ~/.config/gtk-3.0/gtk.css"
|
|
||||||
checked: Settings.data.matugen.gtk3
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.gtk3 = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Qt6ct"
|
|
||||||
description: "Write ~/.config/qt6ct/colors/noctalia.conf"
|
|
||||||
checked: Settings.data.matugen.qt6
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.qt6 = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Qt5ct"
|
|
||||||
description: "Write ~/.config/qt5ct/colors/noctalia.conf"
|
|
||||||
checked: Settings.data.matugen.qt5
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.qt5 = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Kitty"
|
|
||||||
description: "Write ~/.config/kitty/themes/noctalia.conf and reload"
|
|
||||||
checked: Settings.data.matugen.kitty
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.kitty = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Ghostty"
|
|
||||||
description: "Write ~/.config/ghostty/themes/noctalia and reload"
|
|
||||||
checked: Settings.data.matugen.ghostty
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.ghostty = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Foot"
|
|
||||||
description: "Write ~/.config/foot/themes/noctalia and reload"
|
|
||||||
checked: Settings.data.matugen.foot
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.foot = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Fuzzel"
|
|
||||||
description: "Write ~/.config/fuzzel/themes/noctalia and reload"
|
|
||||||
checked: Settings.data.matugen.fuzzel
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.fuzzel = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NCheckbox {
|
|
||||||
label: "Vesktop"
|
|
||||||
description: "Write ~/.config/vesktop/themes/noctalia.theme.css"
|
|
||||||
checked: Settings.data.matugen.vesktop
|
|
||||||
onToggled: checked => {
|
|
||||||
Settings.data.matugen.vesktop = checked
|
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NDivider {
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: Style.marginM * scaling
|
label: "Terminal"
|
||||||
Layout.bottomMargin: Style.marginM * scaling
|
description: "Terminal emulator theming."
|
||||||
|
defaultExpanded: false
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Kitty"
|
||||||
|
description: ProgramCheckerService.kittyAvailable ? "Write ~/.config/kitty/themes/noctalia.conf and reload" : "Requires kitty terminal to be installed"
|
||||||
|
checked: Settings.data.matugen.kitty
|
||||||
|
enabled: ProgramCheckerService.kittyAvailable
|
||||||
|
opacity: ProgramCheckerService.kittyAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.kittyAvailable) {
|
||||||
|
Settings.data.matugen.kitty = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Ghostty"
|
||||||
|
description: ProgramCheckerService.ghosttyAvailable ? "Write ~/.config/ghostty/themes/noctalia and reload" : "Requires ghostty terminal to be installed"
|
||||||
|
checked: Settings.data.matugen.ghostty
|
||||||
|
enabled: ProgramCheckerService.ghosttyAvailable
|
||||||
|
opacity: ProgramCheckerService.ghosttyAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.ghosttyAvailable) {
|
||||||
|
Settings.data.matugen.ghostty = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Foot"
|
||||||
|
description: ProgramCheckerService.footAvailable ? "Write ~/.config/foot/themes/noctalia and reload" : "Requires foot terminal to be installed"
|
||||||
|
checked: Settings.data.matugen.foot
|
||||||
|
enabled: ProgramCheckerService.footAvailable
|
||||||
|
opacity: ProgramCheckerService.footAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.footAvailable) {
|
||||||
|
Settings.data.matugen.foot = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NCheckbox {
|
// Applications
|
||||||
label: "User Templates"
|
NCollapsible {
|
||||||
description: "Enable user-defined Matugen config from ~/.config/matugen/config.toml"
|
Layout.fillWidth: true
|
||||||
checked: Settings.data.matugen.enableUserTemplates
|
label: "Programs"
|
||||||
onToggled: checked => {
|
description: "Application-specific theming."
|
||||||
Settings.data.matugen.enableUserTemplates = checked
|
defaultExpanded: false
|
||||||
if (Settings.data.colorSchemes.useWallpaperColors)
|
|
||||||
MatugenService.generateFromWallpaper()
|
NCheckbox {
|
||||||
}
|
label: "Fuzzel"
|
||||||
|
description: ProgramCheckerService.fuzzelAvailable ? "Write ~/.config/fuzzel/themes/noctalia and reload" : "Requires fuzzel launcher to be installed"
|
||||||
|
checked: Settings.data.matugen.fuzzel
|
||||||
|
enabled: ProgramCheckerService.fuzzelAvailable
|
||||||
|
opacity: ProgramCheckerService.fuzzelAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.fuzzelAvailable) {
|
||||||
|
Settings.data.matugen.fuzzel = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Vesktop"
|
||||||
|
description: ProgramCheckerService.vesktopAvailable ? "Write ~/.config/vesktop/themes/noctalia.theme.css" : "Requires vesktop Discord client to be installed"
|
||||||
|
checked: Settings.data.matugen.vesktop
|
||||||
|
enabled: ProgramCheckerService.vesktopAvailable
|
||||||
|
opacity: ProgramCheckerService.vesktopAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.vesktopAvailable) {
|
||||||
|
Settings.data.matugen.vesktop = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "Pywalfox (Firefox)"
|
||||||
|
description: ProgramCheckerService.pywalfoxAvailable ? "Write ~/.cache/wal/colors.json and run pywalfox update" : "Requires pywalfox package to be installed"
|
||||||
|
checked: Settings.data.matugen.pywalfox
|
||||||
|
enabled: ProgramCheckerService.pywalfoxAvailable
|
||||||
|
opacity: ProgramCheckerService.pywalfoxAvailable ? 1.0 : 0.6
|
||||||
|
onToggled: checked => {
|
||||||
|
if (ProgramCheckerService.pywalfoxAvailable) {
|
||||||
|
Settings.data.matugen.pywalfox = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
|
NCollapsible {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: "Misc"
|
||||||
|
description: "Additional configuration options."
|
||||||
|
defaultExpanded: false
|
||||||
|
|
||||||
|
NCheckbox {
|
||||||
|
label: "User Templates"
|
||||||
|
description: "Enable user-defined Matugen config from ~/.config/matugen/config.toml"
|
||||||
|
checked: Settings.data.matugen.enableUserTemplates
|
||||||
|
onToggled: checked => {
|
||||||
|
Settings.data.matugen.enableUserTemplates = checked
|
||||||
|
if (Settings.data.colorSchemes.useWallpaperColors)
|
||||||
|
MatugenService.generateFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
Services/ProgramCheckerService.qml
Normal file
118
Services/ProgramCheckerService.qml
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
// Service to check if various programs are available on the system
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Program availability properties
|
||||||
|
property bool matugenAvailable: false
|
||||||
|
property bool pywalfoxAvailable: false
|
||||||
|
property bool kittyAvailable: false
|
||||||
|
property bool ghosttyAvailable: false
|
||||||
|
property bool footAvailable: false
|
||||||
|
property bool fuzzelAvailable: false
|
||||||
|
property bool vesktopAvailable: false
|
||||||
|
property bool gpuScreenRecorderAvailable: false
|
||||||
|
|
||||||
|
// Signal emitted when all checks are complete
|
||||||
|
signal checksCompleted
|
||||||
|
|
||||||
|
// Programs to check - maps property names to commands
|
||||||
|
readonly property var programsToCheck: ({
|
||||||
|
"matugenAvailable": ["which", "matugen"],
|
||||||
|
"pywalfoxAvailable": ["which", "pywalfox"],
|
||||||
|
"kittyAvailable": ["which", "kitty"],
|
||||||
|
"ghosttyAvailable": ["which", "ghostty"],
|
||||||
|
"footAvailable": ["which", "foot"],
|
||||||
|
"fuzzelAvailable": ["which", "fuzzel"],
|
||||||
|
"vesktopAvailable": ["which", "vesktop"],
|
||||||
|
"gpuScreenRecorderAvailable": ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Internal tracking
|
||||||
|
property int completedChecks: 0
|
||||||
|
property int totalChecks: Object.keys(programsToCheck).length
|
||||||
|
|
||||||
|
// Single reusable Process object
|
||||||
|
Process {
|
||||||
|
id: checker
|
||||||
|
running: false
|
||||||
|
|
||||||
|
property string currentProperty: ""
|
||||||
|
|
||||||
|
onExited: function (exitCode) {
|
||||||
|
// Set the availability property
|
||||||
|
root[currentProperty] = (exitCode === 0)
|
||||||
|
|
||||||
|
// Stop the process to free resources
|
||||||
|
running = false
|
||||||
|
|
||||||
|
// Track completion
|
||||||
|
root.completedChecks++
|
||||||
|
|
||||||
|
// Check next program or emit completion signal
|
||||||
|
if (root.completedChecks >= root.totalChecks) {
|
||||||
|
root.checksCompleted()
|
||||||
|
} else {
|
||||||
|
root.checkNextProgram()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue of programs to check
|
||||||
|
property var checkQueue: []
|
||||||
|
property int currentCheckIndex: 0
|
||||||
|
|
||||||
|
// Function to check the next program in the queue
|
||||||
|
function checkNextProgram() {
|
||||||
|
if (currentCheckIndex >= checkQueue.length)
|
||||||
|
return
|
||||||
|
|
||||||
|
var propertyName = checkQueue[currentCheckIndex]
|
||||||
|
var command = programsToCheck[propertyName]
|
||||||
|
|
||||||
|
checker.currentProperty = propertyName
|
||||||
|
checker.command = command
|
||||||
|
checker.running = true
|
||||||
|
|
||||||
|
currentCheckIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to run all program checks
|
||||||
|
function checkAllPrograms() {
|
||||||
|
// Reset state
|
||||||
|
completedChecks = 0
|
||||||
|
currentCheckIndex = 0
|
||||||
|
checkQueue = Object.keys(programsToCheck)
|
||||||
|
|
||||||
|
// Start first check
|
||||||
|
if (checkQueue.length > 0) {
|
||||||
|
checkNextProgram()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to check a specific program
|
||||||
|
function checkProgram(programProperty) {
|
||||||
|
if (!programsToCheck.hasOwnProperty(programProperty)) {
|
||||||
|
Logger.warn("ProgramChecker", "Unknown program property:", programProperty)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.currentProperty = programProperty
|
||||||
|
checker.command = programsToCheck[programProperty]
|
||||||
|
checker.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize checks when service is created
|
||||||
|
Component.onCompleted: {
|
||||||
|
checkAllPrograms()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,16 +13,13 @@ Singleton {
|
||||||
property bool isRecording: false
|
property bool isRecording: false
|
||||||
property bool isPending: false
|
property bool isPending: false
|
||||||
property string outputPath: ""
|
property string outputPath: ""
|
||||||
property bool isAvailable: false
|
property bool isAvailable: ProgramCheckerService.gpuScreenRecorderAvailable
|
||||||
|
|
||||||
Component.onCompleted: {
|
// Update availability when ProgramCheckerService completes its checks
|
||||||
checkAvailability()
|
Connections {
|
||||||
}
|
target: ProgramCheckerService
|
||||||
|
function onChecksCompleted() {// Availability is now automatically updated via property binding
|
||||||
function checkAvailability() {
|
}
|
||||||
// Detect native or Flatpak gpu-screen-recorder
|
|
||||||
availabilityCheckProcess.command = ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"]
|
|
||||||
availabilityCheckProcess.running = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start or Stop recording
|
// Start or Stop recording
|
||||||
|
|
@ -101,18 +98,6 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Availability check process
|
|
||||||
Process {
|
|
||||||
id: availabilityCheckProcess
|
|
||||||
command: ["sh", "-c", "true"]
|
|
||||||
onExited: function (exitCode, exitStatus) {
|
|
||||||
// exitCode 0 means available, non-zero means unavailable
|
|
||||||
root.isAvailable = (exitCode === 0)
|
|
||||||
}
|
|
||||||
stdout: StdioCollector {}
|
|
||||||
stderr: StdioCollector {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: pendingTimer
|
id: pendingTimer
|
||||||
interval: 2000 // Wait 2 seconds to see if process stays alive
|
interval: 2000 // Wait 2 seconds to see if process stays alive
|
||||||
|
|
|
||||||
193
Widgets/NCollapsible.qml
Normal file
193
Widgets/NCollapsible.qml
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
property string label: ""
|
||||||
|
property string description: ""
|
||||||
|
property bool expanded: false
|
||||||
|
property bool defaultExpanded: false
|
||||||
|
property real contentSpacing: Style.marginM * scaling
|
||||||
|
signal toggled(bool expanded)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// Default property to accept children
|
||||||
|
default property alias content: contentLayout.children
|
||||||
|
|
||||||
|
// Header with clickable area
|
||||||
|
Rectangle {
|
||||||
|
id: headerContainer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: headerContent.implicitHeight + (Style.marginL * scaling * 2)
|
||||||
|
|
||||||
|
// Material 3 style background
|
||||||
|
color: root.expanded ? Color.mSecondary : Color.mSurfaceVariant
|
||||||
|
radius: Style.radiusL * scaling
|
||||||
|
|
||||||
|
// Subtle border
|
||||||
|
border.color: root.expanded ? Color.mOnSecondary : Color.mOutline
|
||||||
|
border.width: Math.max(1, Style.borderS * scaling)
|
||||||
|
|
||||||
|
// Smooth color transitions
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: headerArea
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.expanded = !root.expanded
|
||||||
|
root.toggled(root.expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover effect overlay
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: headerArea.containsMouse ? Color.mOnSurface : Color.transparent
|
||||||
|
opacity: headerArea.containsMouse ? 0.08 : 0
|
||||||
|
radius: headerContainer.radius // Reference the container's radius directly
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationFast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: headerContent
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Style.marginL * scaling
|
||||||
|
spacing: Style.marginM * scaling
|
||||||
|
|
||||||
|
// Expand/collapse icon with rotation animation
|
||||||
|
NIcon {
|
||||||
|
id: chevronIcon
|
||||||
|
icon: "chevron-right"
|
||||||
|
font.pointSize: Style.fontSizeL * scaling
|
||||||
|
color: root.expanded ? Color.mOnSecondary : Color.mOnSurfaceVariant
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
rotation: root.expanded ? 90 : 0
|
||||||
|
Behavior on rotation {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header text content - properly contained
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: root.label
|
||||||
|
font.pointSize: Style.fontSizeL * scaling
|
||||||
|
font.weight: Style.fontWeightSemiBold
|
||||||
|
color: root.expanded ? Color.mOnSecondary : Color.mOnSurface
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: root.description
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
font.weight: Style.fontWeightRegular
|
||||||
|
color: root.expanded ? Color.mOnSecondary : Color.mOnSurfaceVariant
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: root.description !== ""
|
||||||
|
opacity: 0.87
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapsible content with Material 3 styling
|
||||||
|
Rectangle {
|
||||||
|
id: contentContainer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Style.marginS * scaling
|
||||||
|
|
||||||
|
visible: root.expanded
|
||||||
|
color: Color.mSurface
|
||||||
|
radius: Style.radiusL * scaling
|
||||||
|
border.color: Color.mOutline
|
||||||
|
border.width: Math.max(1, Style.borderS * scaling)
|
||||||
|
|
||||||
|
// Dynamic height based on content
|
||||||
|
Layout.preferredHeight: visible ? contentLayout.implicitHeight + (Style.marginL * scaling * 2) : 0
|
||||||
|
|
||||||
|
// Smooth height animation
|
||||||
|
Behavior on Layout.preferredHeight {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content layout
|
||||||
|
ColumnLayout {
|
||||||
|
id: contentLayout
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Style.marginL * scaling
|
||||||
|
spacing: root.contentSpacing
|
||||||
|
|
||||||
|
// Clip content during animation
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade in animation for content
|
||||||
|
opacity: root.expanded ? 1.0 : 0.0
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize expanded state
|
||||||
|
Component.onCompleted: {
|
||||||
|
root.expanded = root.defaultExpanded
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue