qmlfmt: increase line-length to 360 to avoid hard-wrap.
+ cleaned up power menu/panel
This commit is contained in:
parent
1043eaa39f
commit
7d2eaa46e6
65 changed files with 151 additions and 318 deletions
|
|
@ -51,22 +51,19 @@ Singleton {
|
||||||
lines.push("\n[templates.ghostty]")
|
lines.push("\n[templates.ghostty]")
|
||||||
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/ghostty.conf"')
|
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/ghostty.conf"')
|
||||||
lines.push('output_path = "~/.config/ghostty/themes/noctalia"')
|
lines.push('output_path = "~/.config/ghostty/themes/noctalia"')
|
||||||
lines.push(
|
lines.push("post_hook = \"grep -q '^theme *= *' ~/.config/ghostty/config; and sed -i 's/^theme *= *.*/theme = noctalia/' ~/.config/ghostty/config; or echo 'theme = noctalia' >> ~/.config/ghostty/config\"")
|
||||||
"post_hook = \"grep -q '^theme *= *' ~/.config/ghostty/config; and sed -i 's/^theme *= *.*/theme = noctalia/' ~/.config/ghostty/config; or echo 'theme = noctalia' >> ~/.config/ghostty/config\"")
|
|
||||||
}
|
}
|
||||||
if (Settings.data.matugen.foot) {
|
if (Settings.data.matugen.foot) {
|
||||||
lines.push("\n[templates.foot]")
|
lines.push("\n[templates.foot]")
|
||||||
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/foot.conf"')
|
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/foot.conf"')
|
||||||
lines.push('output_path = "~/.config/foot/themes/noctalia"')
|
lines.push('output_path = "~/.config/foot/themes/noctalia"')
|
||||||
lines.push(
|
lines.push('post_hook = "sed -i /themes/d ~/.config/foot/foot.ini && echo include=~/.config/foot/themes/noctalia >> ~/.config/foot/foot.ini"')
|
||||||
'post_hook = "sed -i /themes/d ~/.config/foot/foot.ini && echo include=~/.config/foot/themes/noctalia >> ~/.config/foot/foot.ini"')
|
|
||||||
}
|
}
|
||||||
if (Settings.data.matugen.fuzzel) {
|
if (Settings.data.matugen.fuzzel) {
|
||||||
lines.push("\n[templates.fuzzel]")
|
lines.push("\n[templates.fuzzel]")
|
||||||
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/fuzzel.conf"')
|
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/fuzzel.conf"')
|
||||||
lines.push('output_path = "~/.config/fuzzel/themes/noctalia"')
|
lines.push('output_path = "~/.config/fuzzel/themes/noctalia"')
|
||||||
lines.push(
|
lines.push('post_hook = "sed -i /themes/d ~/.config/fuzzel/fuzzel.ini && echo include=~/.config/fuzzel/themes/noctalia >> ~/.config/fuzzel/fuzzel.ini"')
|
||||||
'post_hook = "sed -i /themes/d ~/.config/fuzzel/fuzzel.ini && echo include=~/.config/fuzzel/themes/noctalia >> ~/.config/fuzzel/fuzzel.ini"')
|
|
||||||
}
|
}
|
||||||
if (Settings.data.matugen.vesktop) {
|
if (Settings.data.matugen.vesktop) {
|
||||||
lines.push("\n[templates.vesktop]")
|
lines.push("\n[templates.vesktop]")
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@
|
||||||
# Can be installed from AUR "qmlfmt-git"
|
# Can be installed from AUR "qmlfmt-git"
|
||||||
# Requires qt6-5compat
|
# Requires qt6-5compat
|
||||||
|
|
||||||
find . -name "*.qml" -print -exec qmlfmt -e -b 120 -t 2 -i 2 -w {} \;
|
find . -name "*.qml" -print -exec qmlfmt -e -b 360 -t 2 -i 2 -w {} \;
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,7 @@ Singleton {
|
||||||
try {
|
try {
|
||||||
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
||||||
return iconFromName(fallback, fallback)
|
return iconFromName(fallback, fallback)
|
||||||
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(
|
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(appId) : DesktopEntries.byId(appId)
|
||||||
appId) : DesktopEntries.byId(appId)
|
|
||||||
const name = entry && entry.icon ? entry.icon : ""
|
const name = entry && entry.icon ? entry.icon : ""
|
||||||
return iconFromName(name || fallback, fallback)
|
return iconFromName(name || fallback, fallback)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,8 @@ Singleton {
|
||||||
// Default config directory: ~/.config/noctalia
|
// Default config directory: ~/.config/noctalia
|
||||||
// Default cache directory: ~/.cache/noctalia
|
// Default cache directory: ~/.cache/noctalia
|
||||||
property string shellName: "noctalia"
|
property string shellName: "noctalia"
|
||||||
property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME")
|
property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/"
|
||||||
|| Quickshell.env(
|
property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env("HOME") + "/.cache") + "/" + shellName + "/"
|
||||||
"HOME") + "/.config") + "/" + shellName + "/"
|
|
||||||
property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env(
|
|
||||||
"HOME") + "/.cache") + "/" + shellName + "/"
|
|
||||||
property string cacheDirImages: cacheDir + "images/"
|
property string cacheDirImages: cacheDir + "images/"
|
||||||
|
|
||||||
property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json")
|
property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json")
|
||||||
|
|
@ -58,8 +55,7 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasValidBarMonitor) {
|
if (!hasValidBarMonitor) {
|
||||||
Logger.warn("Settings",
|
Logger.warn("Settings", "No configured bar monitors found on system, clearing bar monitor list to show on all screens")
|
||||||
"No configured bar monitors found on system, clearing bar monitor list to show on all screens")
|
|
||||||
adapter.bar.monitors = []
|
adapter.bar.monitors = []
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -138,8 +134,7 @@ Singleton {
|
||||||
widget.showIcon = widget.showIcon !== undefined ? widget.showIcon : adapter.bar.showActiveWindowIcon
|
widget.showIcon = widget.showIcon !== undefined ? widget.showIcon : adapter.bar.showActiveWindowIcon
|
||||||
break
|
break
|
||||||
case "Battery":
|
case "Battery":
|
||||||
widget.alwaysShowPercentage = widget.alwaysShowPercentage
|
widget.alwaysShowPercentage = widget.alwaysShowPercentage !== undefined ? widget.alwaysShowPercentage : adapter.bar.alwaysShowBatteryPercentage
|
||||||
!== undefined ? widget.alwaysShowPercentage : adapter.bar.alwaysShowBatteryPercentage
|
|
||||||
break
|
break
|
||||||
case "Clock":
|
case "Clock":
|
||||||
widget.use12HourClock = widget.use12HourClock !== undefined ? widget.use12HourClock : adapter.location.use12HourClock
|
widget.use12HourClock = widget.use12HourClock !== undefined ? widget.use12HourClock : adapter.location.use12HourClock
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,7 @@ Variants {
|
||||||
|
|
||||||
// Fillmode default is "crop"
|
// Fillmode default is "crop"
|
||||||
property real fillMode: 1.0
|
property real fillMode: 1.0
|
||||||
property vector4d fillColor: Qt.vector4d(Settings.data.wallpaper.fillColor.r,
|
property vector4d fillColor: Qt.vector4d(Settings.data.wallpaper.fillColor.r, Settings.data.wallpaper.fillColor.g, Settings.data.wallpaper.fillColor.b, 1.0)
|
||||||
Settings.data.wallpaper.fillColor.g,
|
|
||||||
Settings.data.wallpaper.fillColor.b, 1.0)
|
|
||||||
|
|
||||||
// On startup assign wallpaper immediately
|
// On startup assign wallpaper immediately
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
@ -229,8 +227,7 @@ Variants {
|
||||||
from: 0.0
|
from: 0.0
|
||||||
to: 1.0
|
to: 1.0
|
||||||
// The stripes shader feels faster visually, we make it a bit slower here.
|
// The stripes shader feels faster visually, we make it a bit slower here.
|
||||||
duration: transitionType == "stripes" ? Settings.data.wallpaper.transitionDuration
|
duration: transitionType == "stripes" ? Settings.data.wallpaper.transitionDuration * 1.6 : Settings.data.wallpaper.transitionDuration
|
||||||
* 1.6 : Settings.data.wallpaper.transitionDuration
|
|
||||||
easing.type: Easing.InOutCubic
|
easing.type: Easing.InOutCubic
|
||||||
onFinished: {
|
onFinished: {
|
||||||
// Swap images after transition completes
|
// Swap images after transition completes
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,7 @@ Variants {
|
||||||
// Make the overview darker
|
// Make the overview darker
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Settings.data.colorSchemes.darkMode ? Qt.alpha(Color.mSurface,
|
color: Settings.data.colorSchemes.darkMode ? Qt.alpha(Color.mSurface, Style.opacityMedium) : Qt.alpha(Color.mOnSurface, Style.opacityMedium)
|
||||||
Style.opacityMedium) : Qt.alpha(Color.mOnSurface,
|
|
||||||
Style.opacityMedium)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,8 @@ Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
margins {
|
margins {
|
||||||
top: ((modelData && Settings.data.bar.monitors.includes(modelData.name))
|
top: ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
|
||||||
|| (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top"
|
bottom: ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
|
||||||
&& Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
|
|
||||||
bottom: ((modelData && Settings.data.bar.monitors.includes(modelData.name))
|
|
||||||
|| (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom"
|
|
||||||
&& Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mask: Region {}
|
mask: Region {}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,7 @@ Variants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
active: Settings.isLoaded && modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name)
|
active: Settings.isLoaded && modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false
|
||||||
|| (Settings.data.bar.monitors.length === 0)) : false
|
|
||||||
|
|
||||||
sourceComponent: PanelWindow {
|
sourceComponent: PanelWindow {
|
||||||
screen: modelData || null
|
screen: modelData || null
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ PopupWindow {
|
||||||
implicitWidth: menuWidth * scaling
|
implicitWidth: menuWidth * scaling
|
||||||
|
|
||||||
// Use the content height of the Flickable for implicit height
|
// Use the content height of the Flickable for implicit height
|
||||||
implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9,
|
implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2 * scaling))
|
||||||
flickable.contentHeight + (Style.marginS * 2 * scaling))
|
|
||||||
visible: false
|
visible: false
|
||||||
color: Color.transparent
|
color: Color.transparent
|
||||||
anchor.item: anchorItem
|
anchor.item: anchorItem
|
||||||
|
|
@ -159,8 +158,7 @@ PopupWindow {
|
||||||
NText {
|
NText {
|
||||||
id: text
|
id: text
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: (modelData?.enabled
|
color: (modelData?.enabled ?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant
|
||||||
?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant
|
|
||||||
text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..."
|
text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..."
|
||||||
font.pointSize: Style.fontSizeS * scaling
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,8 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||||
readonly property bool alwaysShowPercentage: widgetSettings.alwaysShowPercentage
|
readonly property bool alwaysShowPercentage: widgetSettings.alwaysShowPercentage !== undefined ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
readonly property real warningThreshold: widgetSettings.warningThreshold !== undefined ? widgetSettings.warningThreshold : widgetMetadata.warningThreshold
|
||||||
readonly property real warningThreshold: widgetSettings.warningThreshold
|
|
||||||
!== undefined ? widgetSettings.warningThreshold : widgetMetadata.warningThreshold
|
|
||||||
|
|
||||||
// Test mode
|
// Test mode
|
||||||
readonly property bool testMode: false
|
readonly property bool testMode: false
|
||||||
|
|
@ -42,8 +40,7 @@ Item {
|
||||||
|
|
||||||
// Main properties
|
// Main properties
|
||||||
readonly property var battery: UPower.displayDevice
|
readonly property var battery: UPower.displayDevice
|
||||||
readonly property bool isReady: testMode ? true : (battery && battery.ready && battery.isLaptopBattery
|
readonly property bool isReady: testMode ? true : (battery && battery.ready && battery.isLaptopBattery && battery.isPresent)
|
||||||
&& battery.isPresent)
|
|
||||||
readonly property real percent: testMode ? testPercent : (isReady ? (battery.percentage * 100) : 0)
|
readonly property real percent: testMode ? testPercent : (isReady ? (battery.percentage * 100) : 0)
|
||||||
readonly property bool charging: testMode ? testCharging : (isReady ? battery.state === UPowerDeviceState.Charging : false)
|
readonly property bool charging: testMode ? testCharging : (isReady ? battery.state === UPowerDeviceState.Charging : false)
|
||||||
property bool hasNotifiedLowBattery: false
|
property bool hasNotifiedLowBattery: false
|
||||||
|
|
@ -88,8 +85,7 @@ Item {
|
||||||
id: pill
|
id: pill
|
||||||
|
|
||||||
rightOpen: BarWidgetRegistry.getNPillDirection(root)
|
rightOpen: BarWidgetRegistry.getNPillDirection(root)
|
||||||
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent,
|
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady)
|
||||||
charging, isReady)
|
|
||||||
text: (isReady || testMode) ? Math.round(percent) + "%" : "-"
|
text: (isReady || testMode) ? Math.round(percent) + "%" : "-"
|
||||||
autoHide: false
|
autoHide: false
|
||||||
forceOpen: isReady && (testMode || battery.isLaptopBattery) && alwaysShowPercentage
|
forceOpen: isReady && (testMode || battery.isLaptopBattery) && alwaysShowPercentage
|
||||||
|
|
@ -112,8 +108,7 @@ Item {
|
||||||
if (battery.changeRate !== undefined) {
|
if (battery.changeRate !== undefined) {
|
||||||
const rate = battery.changeRate
|
const rate = battery.changeRate
|
||||||
if (rate > 0) {
|
if (rate > 0) {
|
||||||
lines.push(charging ? "Charging rate: " + rate.toFixed(2) + " W." : "Discharging rate: " + rate.toFixed(
|
lines.push(charging ? "Charging rate: " + rate.toFixed(2) + " W." : "Discharging rate: " + rate.toFixed(2) + " W.")
|
||||||
2) + " W.")
|
|
||||||
} else if (rate < 0) {
|
} else if (rate < 0) {
|
||||||
lines.push("Discharging rate: " + Math.abs(rate).toFixed(2) + " W.")
|
lines.push("Discharging rate: " + Math.abs(rate).toFixed(2) + " W.")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ Item {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool userAlwaysShowPercentage: (widgetSettings.alwaysShowPercentage
|
readonly property bool userAlwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
// Used to avoid opening the pill on Quickshell startup
|
// Used to avoid opening the pill on Quickshell startup
|
||||||
property bool firstBrightnessReceived: false
|
property bool firstBrightnessReceived: false
|
||||||
|
|
@ -88,8 +87,7 @@ Item {
|
||||||
var monitor = getMonitor()
|
var monitor = getMonitor()
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
return ""
|
return ""
|
||||||
return "Brightness: " + Math.round(monitor.brightness * 100) + "%\nMethod: " + monitor.method
|
return "Brightness: " + Math.round(monitor.brightness * 100) + "%\nMethod: " + monitor.method + "\nLeft click for advanced settings.\nScroll up/down to change brightness."
|
||||||
+ "\nLeft click for advanced settings.\nScroll up/down to change brightness."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWheel: function (angle) {
|
onWheel: function (angle) {
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,8 @@ Rectangle {
|
||||||
|
|
||||||
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||||
readonly property bool use12h: widgetSettings.use12HourClock !== undefined ? widgetSettings.use12HourClock : widgetMetadata.use12HourClock
|
readonly property bool use12h: widgetSettings.use12HourClock !== undefined ? widgetSettings.use12HourClock : widgetMetadata.use12HourClock
|
||||||
readonly property bool reverseDayMonth: widgetSettings.reverseDayMonth
|
readonly property bool reverseDayMonth: widgetSettings.reverseDayMonth !== undefined ? widgetSettings.reverseDayMonth : widgetMetadata.reverseDayMonth
|
||||||
!== undefined ? widgetSettings.reverseDayMonth : widgetMetadata.reverseDayMonth
|
readonly property string displayFormat: widgetSettings.displayFormat !== undefined ? widgetSettings.displayFormat : widgetMetadata.displayFormat
|
||||||
readonly property string displayFormat: widgetSettings.displayFormat
|
|
||||||
!== undefined ? widgetSettings.displayFormat : widgetMetadata.displayFormat
|
|
||||||
|
|
||||||
implicitWidth: Math.round(layout.implicitWidth + Style.marginM * 2 * scaling)
|
implicitWidth: Math.round(layout.implicitWidth + Style.marginM * 2 * scaling)
|
||||||
implicitHeight: Math.round(Style.capsuleHeight * scaling)
|
implicitHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,9 @@ RowLayout {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool showAlbumArt: (widgetSettings.showAlbumArt
|
readonly property bool showAlbumArt: (widgetSettings.showAlbumArt !== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt
|
||||||
!== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt
|
readonly property bool showVisualizer: (widgetSettings.showVisualizer !== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer
|
||||||
readonly property bool showVisualizer: (widgetSettings.showVisualizer
|
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType !== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
|
||||||
!== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer
|
|
||||||
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType
|
|
||||||
!== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
|
|
||||||
|
|
||||||
// 6% of total width
|
// 6% of total width
|
||||||
readonly property real minWidth: Math.max(1, screen.width * 0.06)
|
readonly property real minWidth: Math.max(1, screen.width * 0.06)
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ Item {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage
|
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
// Used to avoid opening the pill on Quickshell startup
|
// Used to avoid opening the pill on Quickshell startup
|
||||||
property bool firstInputVolumeReceived: false
|
property bool firstInputVolumeReceived: false
|
||||||
|
|
@ -94,8 +93,7 @@ Item {
|
||||||
autoHide: false // Important to be false so we can hover as long as we want
|
autoHide: false // Important to be false so we can hover as long as we want
|
||||||
text: Math.floor(AudioService.inputVolume * 100) + "%"
|
text: Math.floor(AudioService.inputVolume * 100) + "%"
|
||||||
forceOpen: alwaysShowPercentage
|
forceOpen: alwaysShowPercentage
|
||||||
tooltipText: "Microphone: " + Math.round(AudioService.inputVolume * 100)
|
tooltipText: "Microphone: " + Math.round(AudioService.inputVolume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
|
||||||
+ "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
|
|
||||||
|
|
||||||
onWheel: function (delta) {
|
onWheel: function (delta) {
|
||||||
wheelAccumulator += delta
|
wheelAccumulator += delta
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,8 @@ NIconButton {
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge
|
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge !== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
|
||||||
!== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
|
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero !== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
|
||||||
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero
|
|
||||||
!== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
|
|
||||||
|
|
||||||
function lastSeenTs() {
|
function lastSeenTs() {
|
||||||
return Settings.data.notifications?.lastSeenTs || 0
|
return Settings.data.notifications?.lastSeenTs || 0
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,7 @@ NIconButton {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
|
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo !== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
|
||||||
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
|
|
||||||
|
|
||||||
icon: useDistroLogo ? "" : "noctalia"
|
icon: useDistroLogo ? "" : "noctalia"
|
||||||
tooltipText: "Open side panel."
|
tooltipText: "Open side panel."
|
||||||
|
|
|
||||||
|
|
@ -28,17 +28,12 @@ RowLayout {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool showCpuUsage: (widgetSettings.showCpuUsage
|
readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage
|
||||||
!== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage
|
|
||||||
readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp
|
readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp
|
||||||
readonly property bool showMemoryUsage: (widgetSettings.showMemoryUsage
|
readonly property bool showMemoryUsage: (widgetSettings.showMemoryUsage !== undefined) ? widgetSettings.showMemoryUsage : widgetMetadata.showMemoryUsage
|
||||||
!== undefined) ? widgetSettings.showMemoryUsage : widgetMetadata.showMemoryUsage
|
readonly property bool showMemoryAsPercent: (widgetSettings.showMemoryAsPercent !== undefined) ? widgetSettings.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
|
||||||
readonly property bool showMemoryAsPercent: (widgetSettings.showMemoryAsPercent
|
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
|
||||||
!== undefined) ? widgetSettings.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
|
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
|
||||||
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats
|
|
||||||
!== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
|
|
||||||
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage
|
|
||||||
!== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ Item {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage
|
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
// Used to avoid opening the pill on Quickshell startup
|
// Used to avoid opening the pill on Quickshell startup
|
||||||
property bool firstVolumeReceived: false
|
property bool firstVolumeReceived: false
|
||||||
|
|
@ -79,8 +78,7 @@ Item {
|
||||||
autoHide: false // Important to be false so we can hover as long as we want
|
autoHide: false // Important to be false so we can hover as long as we want
|
||||||
text: Math.floor(AudioService.volume * 100) + "%"
|
text: Math.floor(AudioService.volume * 100) + "%"
|
||||||
forceOpen: alwaysShowPercentage
|
forceOpen: alwaysShowPercentage
|
||||||
tooltipText: "Volume: " + Math.round(AudioService.volume * 100)
|
tooltipText: "Volume: " + Math.round(AudioService.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
|
||||||
+ "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
|
|
||||||
|
|
||||||
onWheel: function (delta) {
|
onWheel: function (delta) {
|
||||||
wheelAccumulator += delta
|
wheelAccumulator += delta
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
||||||
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied
|
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied
|
||||||
!== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied
|
|
||||||
|
|
||||||
property bool isDestroying: false
|
property bool isDestroying: false
|
||||||
property bool hovered: false
|
property bool hovered: false
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,7 @@ ColumnLayout {
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||||
text: (modelData.signalStrength !== undefined
|
text: (modelData.signalStrength !== undefined && modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
||||||
&& modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
|
||||||
font.pointSize: Style.fontSizeXS * scaling
|
font.pointSize: Style.fontSizeXS * scaling
|
||||||
color: getContentColor(Color.mOnSurface)
|
color: getContentColor(Color.mOnSurface)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,7 @@ NPanel {
|
||||||
property var items: {
|
property var items: {
|
||||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||||
return []
|
return []
|
||||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.connected
|
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.connected && (dev.paired || dev.trusted))
|
||||||
&& (dev.paired || dev.trusted))
|
|
||||||
return BluetoothService.sortDevices(filtered)
|
return BluetoothService.sortDevices(filtered)
|
||||||
}
|
}
|
||||||
model: items
|
model: items
|
||||||
|
|
@ -176,10 +175,7 @@ NPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||||
return dev && !dev.paired && !dev.pairing
|
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0)
|
||||||
&& !dev.blocked
|
|
||||||
&& (dev.signalStrength === undefined
|
|
||||||
|| dev.signalStrength > 0)
|
|
||||||
}).length
|
}).length
|
||||||
return (availableCount === 0)
|
return (availableCount === 0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ Variants {
|
||||||
readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL * scaling
|
readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL * scaling
|
||||||
|
|
||||||
// Bar detection and positioning properties
|
// Bar detection and positioning properties
|
||||||
readonly property bool hasBar: modelData.name ? (Settings.data.bar.monitors.includes(modelData.name)
|
readonly property bool hasBar: modelData.name ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false
|
||||||
|| (Settings.data.bar.monitors.length === 0)) : false
|
|
||||||
readonly property bool barAtBottom: hasBar && Settings.data.bar.position === "bottom"
|
readonly property bool barAtBottom: hasBar && Settings.data.bar.position === "bottom"
|
||||||
readonly property int barHeight: Style.barHeight * scaling
|
readonly property int barHeight: Style.barHeight * scaling
|
||||||
|
|
||||||
|
|
@ -261,8 +260,7 @@ Variants {
|
||||||
Layout.preferredHeight: iconSize
|
Layout.preferredHeight: iconSize
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
|
||||||
property bool isActive: ToplevelManager.activeToplevel
|
property bool isActive: ToplevelManager.activeToplevel && ToplevelManager.activeToplevel === modelData
|
||||||
&& ToplevelManager.activeToplevel === modelData
|
|
||||||
property bool hovered: appMouseArea.containsMouse
|
property bool hovered: appMouseArea.containsMouse
|
||||||
property string appId: modelData ? modelData.appId : ""
|
property string appId: modelData ? modelData.appId : ""
|
||||||
property string appTitle: modelData ? modelData.title : ""
|
property string appTitle: modelData ? modelData.title : ""
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,7 @@ Item {
|
||||||
|
|
||||||
if (!query || query.trim() === "") {
|
if (!query || query.trim() === "") {
|
||||||
// Return all apps alphabetically
|
// Return all apps alphabetically
|
||||||
return entries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(
|
return entries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(app => createResultEntry(app))
|
||||||
app => createResultEntry(app))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use fuzzy search if available, fallback to simple search
|
// Use fuzzy search if available, fallback to simple search
|
||||||
|
|
@ -57,8 +56,7 @@ Item {
|
||||||
const name = (app.name || "").toLowerCase()
|
const name = (app.name || "").toLowerCase()
|
||||||
const comment = (app.comment || "").toLowerCase()
|
const comment = (app.comment || "").toLowerCase()
|
||||||
const generic = (app.genericName || "").toLowerCase()
|
const generic = (app.genericName || "").toLowerCase()
|
||||||
return name.includes(searchTerm) || comment.includes(searchTerm) || generic.includes(
|
return name.includes(searchTerm) || comment.includes(searchTerm) || generic.includes(searchTerm)
|
||||||
searchTerm)
|
|
||||||
}).sort((a, b) => {
|
}).sort((a, b) => {
|
||||||
// Prioritize name matches
|
// Prioritize name matches
|
||||||
const aName = a.name.toLowerCase()
|
const aName = a.name.toLowerCase()
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@ Item {
|
||||||
|
|
||||||
function handleCommand(query) {
|
function handleCommand(query) {
|
||||||
// Handle >calc command or direct math expressions after >
|
// Handle >calc command or direct math expressions after >
|
||||||
return query.startsWith(">calc") || (query.startsWith(">") && query.length > 1 && isMathExpression(
|
return query.startsWith(">calc") || (query.startsWith(">") && query.length > 1 && isMathExpression(query.substring(1)))
|
||||||
query.substring(1)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function commands() {
|
function commands() {
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,7 @@ Scope {
|
||||||
user: Quickshell.env("USER")
|
user: Quickshell.env("USER")
|
||||||
|
|
||||||
onPamMessage: {
|
onPamMessage: {
|
||||||
Logger.log("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:",
|
Logger.log("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired)
|
||||||
responseRequired)
|
|
||||||
|
|
||||||
if (messageIsError) {
|
if (messageIsError) {
|
||||||
errorMessage = message
|
errorMessage = message
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,7 @@ Loader {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: keyboardLayout
|
id: keyboardLayout
|
||||||
property string currentLayout: (typeof KeyboardLayoutService !== 'undefined'
|
property string currentLayout: (typeof KeyboardLayoutService !== 'undefined' && KeyboardLayoutService.currentLayout) ? KeyboardLayoutService.currentLayout : "Unknown"
|
||||||
&& KeyboardLayoutService.currentLayout) ? KeyboardLayoutService.currentLayout : "Unknown"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
|
|
@ -227,12 +226,10 @@ Loader {
|
||||||
Repeater {
|
Repeater {
|
||||||
model: CavaService.values.length * 2
|
model: CavaService.values.length * 2
|
||||||
Rectangle {
|
Rectangle {
|
||||||
property int mirroredValueIndex: index < CavaService.values.length ? index : (CavaService.values.length
|
property int mirroredValueIndex: index < CavaService.values.length ? index : (CavaService.values.length * 2 - 1 - index)
|
||||||
* 2 - 1 - index)
|
|
||||||
property real mirroredAngle: (index / (CavaService.values.length * 2)) * 2 * Math.PI
|
property real mirroredAngle: (index / (CavaService.values.length * 2)) * 2 * Math.PI
|
||||||
property real mirroredRadius: 70 * scaling
|
property real mirroredRadius: 70 * scaling
|
||||||
property real mirroredBarLength: Math.max(
|
property real mirroredBarLength: Math.max(2, CavaService.values[mirroredValueIndex] * 30 * scaling)
|
||||||
2, CavaService.values[mirroredValueIndex] * 30 * scaling)
|
|
||||||
property real mirroredBarWidth: 3 * scaling
|
property real mirroredBarWidth: 3 * scaling
|
||||||
width: mirroredBarWidth
|
width: mirroredBarWidth
|
||||||
height: mirroredBarLength
|
height: mirroredBarLength
|
||||||
|
|
@ -428,8 +425,7 @@ Loader {
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
visible: batteryIndicator.batteryVisible
|
visible: batteryIndicator.batteryVisible
|
||||||
NIcon {
|
NIcon {
|
||||||
icon: BatteryService.getIcon(batteryIndicator.percent, batteryIndicator.charging,
|
icon: BatteryService.getIcon(batteryIndicator.percent, batteryIndicator.charging, batteryIndicator.isReady)
|
||||||
batteryIndicator.isReady)
|
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
font.pointSize: Style.fontSizeM * scaling
|
||||||
color: batteryIndicator.charging ? Color.mPrimary : Color.mOnSurface
|
color: batteryIndicator.charging ? Color.mPrimary : Color.mOnSurface
|
||||||
rotation: -90
|
rotation: -90
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,7 @@ Variants {
|
||||||
property var removingNotifications: ({})
|
property var removingNotifications: ({})
|
||||||
|
|
||||||
// If no notification display activated in settings, then show them all
|
// If no notification display activated in settings, then show them all
|
||||||
active: Settings.isLoaded && modelData
|
active: Settings.isLoaded && modelData && (NotificationService.notificationModel.count > 0) ? (Settings.data.notifications.monitors.includes(modelData.name) || (Settings.data.notifications.monitors.length === 0)) : false
|
||||||
&& (NotificationService.notificationModel.count > 0) ? (Settings.data.notifications.monitors.includes(
|
|
||||||
modelData.name)
|
|
||||||
|| (Settings.data.notifications.monitors.length === 0)) : false
|
|
||||||
|
|
||||||
visible: (NotificationService.notificationModel.count > 0)
|
visible: (NotificationService.notificationModel.count > 0)
|
||||||
|
|
||||||
|
|
@ -181,8 +178,7 @@ Variants {
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: `${(model.appName || model.desktopEntry)
|
text: `${(model.appName || model.desktopEntry) || "Unknown App"} · ${NotificationService.formatTimestamp(model.timestamp)}`
|
||||||
|| "Unknown App"} · ${NotificationService.formatTimestamp(model.timestamp)}`
|
|
||||||
color: Color.mSecondary
|
color: Color.mSecondary
|
||||||
font.pointSize: Style.fontSizeXS * scaling
|
font.pointSize: Style.fontSizeXS * scaling
|
||||||
}
|
}
|
||||||
|
|
@ -249,8 +245,7 @@ Variants {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
visible: model.rawNotification && model.rawNotification.actions
|
visible: model.rawNotification && model.rawNotification.actions && model.rawNotification.actions.length > 0
|
||||||
&& model.rawNotification.actions.length > 0
|
|
||||||
|
|
||||||
property var notificationActions: model.rawNotification ? model.rawNotification.actions : []
|
property var notificationActions: model.rawNotification ? model.rawNotification.actions : []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,13 +152,7 @@ NPanel {
|
||||||
Layout.preferredHeight: 28 * scaling
|
Layout.preferredHeight: 28 * scaling
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
// Prefer stable themed icons over transient image paths
|
// Prefer stable themed icons over transient image paths
|
||||||
imagePath: (appIcon
|
imagePath: (appIcon && appIcon !== "") ? (AppIcons.iconFromName(appIcon, "application-x-executable") || appIcon) : ((AppIcons.iconForAppId(desktopEntry || appName, "application-x-executable") || (image && image !== "" ? image : AppIcons.iconFromName("application-x-executable", "application-x-executable"))))
|
||||||
&& appIcon !== "") ? (AppIcons.iconFromName(appIcon, "application-x-executable")
|
|
||||||
|| appIcon) : ((AppIcons.iconForAppId(desktopEntry
|
|
||||||
|| appName, "application-x-executable")
|
|
||||||
|| (image && image
|
|
||||||
!== "" ? image : AppIcons.iconFromName("application-x-executable",
|
|
||||||
"application-x-executable"))))
|
|
||||||
borderColor: Color.transparent
|
borderColor: Color.transparent
|
||||||
borderWidth: 0
|
borderWidth: 0
|
||||||
visible: true
|
visible: true
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ NPanel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
preferredWidth: 440
|
preferredWidth: 440
|
||||||
preferredHeight: 380
|
preferredHeight: 410
|
||||||
panelAnchorHorizontalCenter: true
|
panelAnchorHorizontalCenter: true
|
||||||
panelAnchorVerticalCenter: true
|
panelAnchorVerticalCenter: true
|
||||||
panelKeyboardFocus: true
|
panelKeyboardFocus: true
|
||||||
|
|
@ -263,8 +263,7 @@ NPanel {
|
||||||
Layout.preferredHeight: Style.baseWidgetSize * 0.8 * scaling
|
Layout.preferredHeight: Style.baseWidgetSize * 0.8 * scaling
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: timerActive ? `${pendingAction.charAt(0).toUpperCase() + pendingAction.slice(1)} in ${Math.ceil(
|
text: timerActive ? `${pendingAction.charAt(0).toUpperCase() + pendingAction.slice(1)} in ${Math.ceil(timeRemaining / 1000)} seconds...` : "Power Menu"
|
||||||
timeRemaining / 1000)} seconds...` : "Power Options"
|
|
||||||
font.weight: Style.fontWeightBold
|
font.weight: Style.fontWeightBold
|
||||||
font.pointSize: Style.fontSizeL * scaling
|
font.pointSize: Style.fontSizeL * scaling
|
||||||
color: timerActive ? Color.mPrimary : Color.mOnSurface
|
color: timerActive ? Color.mPrimary : Color.mOnSurface
|
||||||
|
|
@ -293,6 +292,10 @@ NPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NDivider {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
// Power options
|
// Power options
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -338,7 +341,7 @@ NPanel {
|
||||||
return Qt.alpha(Color.mPrimary, 0.08)
|
return Qt.alpha(Color.mPrimary, 0.08)
|
||||||
}
|
}
|
||||||
if (isSelected || mouseArea.containsMouse) {
|
if (isSelected || mouseArea.containsMouse) {
|
||||||
return Color.mSecondary
|
return Color.mTertiary
|
||||||
}
|
}
|
||||||
return Color.transparent
|
return Color.transparent
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +371,7 @@ NPanel {
|
||||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||||
return Color.mError
|
return Color.mError
|
||||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||||
return Color.mOnSecondary
|
return Color.mOnTertiary
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface
|
||||||
}
|
}
|
||||||
font.pointSize: Style.fontSizeXXXL * scaling
|
font.pointSize: Style.fontSizeXXXL * scaling
|
||||||
|
|
@ -402,7 +405,7 @@ NPanel {
|
||||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||||
return Color.mError
|
return Color.mError
|
||||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||||
return Color.mOnSecondary
|
return Color.mOnTertiary
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,7 +430,7 @@ NPanel {
|
||||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||||
return Color.mError
|
return Color.mError
|
||||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||||
return Color.mOnSecondary
|
return Color.mOnTertiary
|
||||||
return Color.mOnSurfaceVariant
|
return Color.mOnSurfaceVariant
|
||||||
}
|
}
|
||||||
opacity: Style.opacityHeavy
|
opacity: Style.opacityHeavy
|
||||||
|
|
|
||||||
|
|
@ -339,12 +339,10 @@ NBox {
|
||||||
continue
|
continue
|
||||||
|
|
||||||
// Check distance to left edge (insert before)
|
// Check distance to left edge (insert before)
|
||||||
const leftDist = Math.sqrt(Math.pow(mouseX - widget.x,
|
const leftDist = Math.sqrt(Math.pow(mouseX - widget.x, 2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))
|
||||||
2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))
|
|
||||||
|
|
||||||
// Check distance to right edge (insert after)
|
// Check distance to right edge (insert after)
|
||||||
const rightDist = Math.sqrt(Math.pow(mouseX - (widget.x + widget.width),
|
const rightDist = Math.sqrt(Math.pow(mouseX - (widget.x + widget.width), 2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))
|
||||||
2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))
|
|
||||||
|
|
||||||
if (leftDist < minDistance) {
|
if (leftDist < minDistance) {
|
||||||
minDistance = leftDist
|
minDistance = leftDist
|
||||||
|
|
@ -355,8 +353,7 @@ NBox {
|
||||||
if (rightDist < minDistance) {
|
if (rightDist < minDistance) {
|
||||||
minDistance = rightDist
|
minDistance = rightDist
|
||||||
bestIndex = i + 1
|
bestIndex = i + 1
|
||||||
bestPosition = Qt.point(widget.x + widget.width + Style.marginXS * scaling - dropIndicator.width / 2,
|
bestPosition = Qt.point(widget.x + widget.width + Style.marginXS * scaling - dropIndicator.width / 2, widget.y)
|
||||||
widget.y)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,8 +365,7 @@ NBox {
|
||||||
if (dist < minDistance && mouseX < firstWidget.x + firstWidget.width / 2) {
|
if (dist < minDistance && mouseX < firstWidget.x + firstWidget.width / 2) {
|
||||||
minDistance = dist
|
minDistance = dist
|
||||||
bestIndex = 0
|
bestIndex = 0
|
||||||
bestPosition = Qt.point(Math.max(0, firstWidget.x - dropIndicator.width - Style.marginS * scaling),
|
bestPosition = Qt.point(Math.max(0, firstWidget.x - dropIndicator.width - Style.marginS * scaling), firstWidget.y)
|
||||||
firstWidget.y)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -419,8 +415,7 @@ NBox {
|
||||||
for (var i = 0; i < widgetModel.length; i++) {
|
for (var i = 0; i < widgetModel.length; i++) {
|
||||||
const widget = widgetFlow.children[i]
|
const widget = widgetFlow.children[i]
|
||||||
if (widget && widget.widgetIndex !== undefined) {
|
if (widget && widget.widgetIndex !== undefined) {
|
||||||
if (mouse.x >= widget.x && mouse.x <= widget.x + widget.width && mouse.y >= widget.y
|
if (mouse.x >= widget.x && mouse.x <= widget.x + widget.width && mouse.y >= widget.y && mouse.y <= widget.y + widget.height) {
|
||||||
&& mouse.y <= widget.y + widget.height) {
|
|
||||||
|
|
||||||
const localX = mouse.x - widget.x
|
const localX = mouse.x - widget.x
|
||||||
const buttonsStartX = widget.width - (widget.buttonsCount * widget.buttonsWidth)
|
const buttonsStartX = widget.width - (widget.buttonsCount * widget.buttonsWidth)
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@ ColumnLayout {
|
||||||
property var widgetMetadata: null
|
property var widgetMetadata: null
|
||||||
|
|
||||||
// Local state
|
// Local state
|
||||||
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage
|
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
|
||||||
property int valueWarningThreshold: widgetData.warningThreshold
|
|
||||||
!== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
|
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {})
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ ColumnLayout {
|
||||||
property var widgetMetadata: null
|
property var widgetMetadata: null
|
||||||
|
|
||||||
// Local state
|
// Local state
|
||||||
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage
|
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {})
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ ColumnLayout {
|
||||||
property var widgetMetadata: null
|
property var widgetMetadata: null
|
||||||
|
|
||||||
// Local state
|
// Local state
|
||||||
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage
|
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {})
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,8 @@ ColumnLayout {
|
||||||
property bool valueShowCpuUsage: widgetData.showCpuUsage !== undefined ? widgetData.showCpuUsage : widgetMetadata.showCpuUsage
|
property bool valueShowCpuUsage: widgetData.showCpuUsage !== undefined ? widgetData.showCpuUsage : widgetMetadata.showCpuUsage
|
||||||
property bool valueShowCpuTemp: widgetData.showCpuTemp !== undefined ? widgetData.showCpuTemp : widgetMetadata.showCpuTemp
|
property bool valueShowCpuTemp: widgetData.showCpuTemp !== undefined ? widgetData.showCpuTemp : widgetMetadata.showCpuTemp
|
||||||
property bool valueShowMemoryUsage: widgetData.showMemoryUsage !== undefined ? widgetData.showMemoryUsage : widgetMetadata.showMemoryUsage
|
property bool valueShowMemoryUsage: widgetData.showMemoryUsage !== undefined ? widgetData.showMemoryUsage : widgetMetadata.showMemoryUsage
|
||||||
property bool valueShowMemoryAsPercent: widgetData.showMemoryAsPercent
|
property bool valueShowMemoryAsPercent: widgetData.showMemoryAsPercent !== undefined ? widgetData.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
|
||||||
!== undefined ? widgetData.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
|
property bool valueShowNetworkStats: widgetData.showNetworkStats !== undefined ? widgetData.showNetworkStats : widgetMetadata.showNetworkStats
|
||||||
property bool valueShowNetworkStats: widgetData.showNetworkStats
|
|
||||||
!== undefined ? widgetData.showNetworkStats : widgetMetadata.showNetworkStats
|
|
||||||
property bool valueShowDiskUsage: widgetData.showDiskUsage !== undefined ? widgetData.showDiskUsage : widgetMetadata.showDiskUsage
|
property bool valueShowDiskUsage: widgetData.showDiskUsage !== undefined ? widgetData.showDiskUsage : widgetMetadata.showDiskUsage
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ ColumnLayout {
|
||||||
property var widgetMetadata: null
|
property var widgetMetadata: null
|
||||||
|
|
||||||
// Local state
|
// Local state
|
||||||
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage
|
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
||||||
!== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
|
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {})
|
||||||
|
|
|
||||||
|
|
@ -227,8 +227,7 @@ NPanel {
|
||||||
if (activeScrollView && activeScrollView.ScrollBar.vertical) {
|
if (activeScrollView && activeScrollView.ScrollBar.vertical) {
|
||||||
const scrollBar = activeScrollView.ScrollBar.vertical
|
const scrollBar = activeScrollView.ScrollBar.vertical
|
||||||
const stepSize = activeScrollView.height * 0.1 // Scroll 10% of viewport
|
const stepSize = activeScrollView.height * 0.1 // Scroll 10% of viewport
|
||||||
scrollBar.position = Math.min(scrollBar.position + stepSize / activeScrollView.contentHeight,
|
scrollBar.position = Math.min(scrollBar.position + stepSize / activeScrollView.contentHeight, 1.0 - scrollBar.size)
|
||||||
1.0 - scrollBar.size)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,8 +243,7 @@ NPanel {
|
||||||
if (activeScrollView && activeScrollView.ScrollBar.vertical) {
|
if (activeScrollView && activeScrollView.ScrollBar.vertical) {
|
||||||
const scrollBar = activeScrollView.ScrollBar.vertical
|
const scrollBar = activeScrollView.ScrollBar.vertical
|
||||||
const pageSize = activeScrollView.height * 0.9 // Scroll 90% of viewport
|
const pageSize = activeScrollView.height * 0.9 // Scroll 90% of viewport
|
||||||
scrollBar.position = Math.min(scrollBar.position + pageSize / activeScrollView.contentHeight,
|
scrollBar.position = Math.min(scrollBar.position + pageSize / activeScrollView.contentHeight, 1.0 - scrollBar.size)
|
||||||
1.0 - scrollBar.size)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,8 +201,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _reorderWidgetInSection(section, fromIndex, toIndex) {
|
function _reorderWidgetInSection(section, fromIndex, toIndex) {
|
||||||
if (fromIndex >= 0 && fromIndex < Settings.data.bar.widgets[section].length && toIndex >= 0
|
if (fromIndex >= 0 && fromIndex < Settings.data.bar.widgets[section].length && toIndex >= 0 && toIndex < Settings.data.bar.widgets[section].length) {
|
||||||
&& toIndex < Settings.data.bar.widgets[section].length) {
|
|
||||||
|
|
||||||
// Create a new array to avoid modifying the original
|
// Create a new array to avoid modifying the original
|
||||||
var newArray = Settings.data.bar.widgets[section].slice()
|
var newArray = Settings.data.bar.widgets[section].slice()
|
||||||
|
|
|
||||||
|
|
@ -276,8 +276,7 @@ ColumnLayout {
|
||||||
// Schedule settings
|
// Schedule settings
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: Style.marginXS * scaling
|
spacing: Style.marginXS * scaling
|
||||||
visible: Settings.data.nightLight.enabled && !Settings.data.nightLight.autoSchedule
|
visible: Settings.data.nightLight.enabled && !Settings.data.nightLight.autoSchedule && !Settings.data.nightLight.forced
|
||||||
&& !Settings.data.nightLight.forced
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
|
|
|
||||||
|
|
@ -186,9 +186,7 @@ ColumnLayout {
|
||||||
radius: Style.radiusM * scaling
|
radius: Style.radiusM * scaling
|
||||||
color: getSchemeColor(modelData, "mSurface")
|
color: getSchemeColor(modelData, "mSurface")
|
||||||
border.width: Math.max(1, Style.borderL * scaling)
|
border.width: Math.max(1, Style.borderL * scaling)
|
||||||
border.color: (!Settings.data.colorSchemes.useWallpaperColors
|
border.color: (!Settings.data.colorSchemes.useWallpaperColors && (Settings.data.colorSchemes.predefinedScheme === modelData.split("/").pop().replace(".json", ""))) ? Color.mSecondary : Color.mOutline
|
||||||
&& (Settings.data.colorSchemes.predefinedScheme === modelData.split("/").pop().replace(
|
|
||||||
".json", ""))) ? Color.mSecondary : Color.mOutline
|
|
||||||
scale: root.cardScaleLow
|
scale: root.cardScaleLow
|
||||||
|
|
||||||
// Mouse area for selection
|
// Mouse area for selection
|
||||||
|
|
@ -281,9 +279,7 @@ ColumnLayout {
|
||||||
|
|
||||||
// Selection indicator (Checkmark)
|
// Selection indicator (Checkmark)
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: !Settings.data.colorSchemes.useWallpaperColors
|
visible: !Settings.data.colorSchemes.useWallpaperColors && (Settings.data.colorSchemes.predefinedScheme === schemePath.split("/").pop().replace(".json", ""))
|
||||||
&& (Settings.data.colorSchemes.predefinedScheme === schemePath.split("/").pop().replace(".json",
|
|
||||||
""))
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.margins: Style.marginS * scaling
|
anchors.margins: Style.marginS * scaling
|
||||||
|
|
|
||||||
|
|
@ -106,11 +106,9 @@ ColumnLayout {
|
||||||
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
|
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
|
||||||
onToggled: checked => {
|
onToggled: checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors,
|
Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, modelData.name)
|
||||||
modelData.name)
|
|
||||||
} else {
|
} else {
|
||||||
Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors,
|
Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, modelData.name)
|
||||||
modelData.name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,9 +232,7 @@ NBox {
|
||||||
return 0
|
return 0
|
||||||
return Math.max(0, Math.min(1, r))
|
return Math.max(0, Math.min(1, r))
|
||||||
}
|
}
|
||||||
property real effectiveRatio: (MediaService.isSeeking
|
property real effectiveRatio: (MediaService.isSeeking && localSeekRatio >= 0) ? Math.max(0, Math.min(1, localSeekRatio)) : progressRatio
|
||||||
&& localSeekRatio >= 0) ? Math.max(0, Math.min(1,
|
|
||||||
localSeekRatio)) : progressRatio
|
|
||||||
|
|
||||||
// Debounced backend seek during drag
|
// Debounced backend seek during drag
|
||||||
Timer {
|
Timer {
|
||||||
|
|
@ -244,8 +242,7 @@ NBox {
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (MediaService.isSeeking && progressWrapper.localSeekRatio >= 0) {
|
if (MediaService.isSeeking && progressWrapper.localSeekRatio >= 0) {
|
||||||
const next = Math.max(0, Math.min(1, progressWrapper.localSeekRatio))
|
const next = Math.max(0, Math.min(1, progressWrapper.localSeekRatio))
|
||||||
if (progressWrapper.lastSentSeekRatio < 0 || Math.abs(
|
if (progressWrapper.lastSentSeekRatio < 0 || Math.abs(next - progressWrapper.lastSentSeekRatio) >= progressWrapper.seekEpsilon) {
|
||||||
next - progressWrapper.lastSentSeekRatio) >= progressWrapper.seekEpsilon) {
|
|
||||||
MediaService.seekByRatio(next)
|
MediaService.seekByRatio(next)
|
||||||
progressWrapper.lastSentSeekRatio = next
|
progressWrapper.lastSentSeekRatio = next
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,7 @@ NBox {
|
||||||
tooltipText: "Set performance power profile."
|
tooltipText: "Set performance power profile."
|
||||||
enabled: hasPP
|
enabled: hasPP
|
||||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||||
colorBg: (enabled
|
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
|
||||||
&& PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
|
|
||||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
|
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
|
@ -44,8 +43,7 @@ NBox {
|
||||||
tooltipText: "Set balanced power profile."
|
tooltipText: "Set balanced power profile."
|
||||||
enabled: hasPP
|
enabled: hasPP
|
||||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||||
colorBg: (enabled
|
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
|
||||||
&& PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
|
|
||||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
|
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
|
@ -59,8 +57,7 @@ NBox {
|
||||||
tooltipText: "Set eco power profile."
|
tooltipText: "Set eco power profile."
|
||||||
enabled: hasPP
|
enabled: hasPP
|
||||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||||
colorBg: (enabled
|
colorBg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
|
||||||
&& PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
|
|
||||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
|
colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ NBox {
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
NIcon {
|
NIcon {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
icon: weatherReady ? LocationService.weatherSymbolFromCode(
|
icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : ""
|
||||||
LocationService.data.weather.current_weather.weathercode) : ""
|
|
||||||
font.pointSize: Style.fontSizeXXXL * 1.75 * scaling
|
font.pointSize: Style.fontSizeXXXL * 1.75 * scaling
|
||||||
color: Color.mPrimary
|
color: Color.mPrimary
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ Variants {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only show on screens that have notifications enabled
|
// Only show on screens that have notifications enabled
|
||||||
active: Settings.isLoaded && modelData ? (Settings.data.notifications.monitors.includes(modelData.name)
|
active: Settings.isLoaded && modelData ? (Settings.data.notifications.monitors.includes(modelData.name) || (Settings.data.notifications.monitors.length === 0)) : false
|
||||||
|| (Settings.data.notifications.monitors.length === 0)) : false
|
|
||||||
|
|
||||||
sourceComponent: PanelWindow {
|
sourceComponent: PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,7 @@ NPanel {
|
||||||
|
|
||||||
// Scanning state
|
// Scanning state
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
visible: Settings.data.network.wifiEnabled && NetworkService.scanning && Object.keys(
|
visible: Settings.data.network.wifiEnabled && NetworkService.scanning && Object.keys(NetworkService.networks).length === 0
|
||||||
NetworkService.networks).length === 0
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: Style.marginL * scaling
|
spacing: Style.marginL * scaling
|
||||||
|
|
||||||
|
|
@ -186,8 +185,7 @@ NPanel {
|
||||||
|
|
||||||
// Networks list container
|
// Networks list container
|
||||||
NScrollView {
|
NScrollView {
|
||||||
visible: Settings.data.network.wifiEnabled && (!NetworkService.scanning || Object.keys(
|
visible: Settings.data.network.wifiEnabled && (!NetworkService.scanning || Object.keys(NetworkService.networks).length > 0)
|
||||||
NetworkService.networks).length > 0)
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
horizontalPolicy: ScrollBar.AlwaysOff
|
horizontalPolicy: ScrollBar.AlwaysOff
|
||||||
verticalPolicy: ScrollBar.AsNeeded
|
verticalPolicy: ScrollBar.AsNeeded
|
||||||
|
|
@ -217,11 +215,9 @@ NPanel {
|
||||||
radius: Style.radiusM * scaling
|
radius: Style.radiusM * scaling
|
||||||
|
|
||||||
// Add opacity for operations in progress
|
// Add opacity for operations in progress
|
||||||
opacity: (NetworkService.disconnectingFrom === modelData.ssid
|
opacity: (NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid) ? 0.6 : 1.0
|
||||||
|| NetworkService.forgettingNetwork === modelData.ssid) ? 0.6 : 1.0
|
|
||||||
|
|
||||||
color: modelData.connected ? Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b,
|
color: modelData.connected ? Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b, 0.05) : Color.mSurface
|
||||||
0.05) : Color.mSurface
|
|
||||||
border.width: Math.max(1, Style.borderS * scaling)
|
border.width: Math.max(1, Style.borderS * scaling)
|
||||||
border.color: modelData.connected ? Color.mPrimary : Color.mOutline
|
border.color: modelData.connected ? Color.mPrimary : Color.mOutline
|
||||||
|
|
||||||
|
|
@ -338,9 +334,7 @@ NPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: modelData.cached && !modelData.connected
|
visible: modelData.cached && !modelData.connected && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
|
||||||
&& NetworkService.forgettingNetwork !== modelData.ssid
|
|
||||||
&& NetworkService.disconnectingFrom !== modelData.ssid
|
|
||||||
color: Color.transparent
|
color: Color.transparent
|
||||||
border.color: Color.mOutline
|
border.color: Color.mOutline
|
||||||
border.width: Math.max(1, Style.borderS * scaling)
|
border.width: Math.max(1, Style.borderS * scaling)
|
||||||
|
|
@ -364,19 +358,14 @@ NPanel {
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
|
||||||
NBusyIndicator {
|
NBusyIndicator {
|
||||||
visible: NetworkService.connectingTo === modelData.ssid
|
visible: NetworkService.connectingTo === modelData.ssid || NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid
|
||||||
|| NetworkService.disconnectingFrom === modelData.ssid
|
|
||||||
|| NetworkService.forgettingNetwork === modelData.ssid
|
|
||||||
running: visible
|
running: visible
|
||||||
color: Color.mPrimary
|
color: Color.mPrimary
|
||||||
size: Style.baseWidgetSize * 0.5 * scaling
|
size: Style.baseWidgetSize * 0.5 * scaling
|
||||||
}
|
}
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
visible: (modelData.existing || modelData.cached) && !modelData.connected
|
visible: (modelData.existing || modelData.cached) && !modelData.connected && NetworkService.connectingTo !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
|
||||||
&& NetworkService.connectingTo !== modelData.ssid
|
|
||||||
&& NetworkService.forgettingNetwork !== modelData.ssid
|
|
||||||
&& NetworkService.disconnectingFrom !== modelData.ssid
|
|
||||||
icon: "trash"
|
icon: "trash"
|
||||||
tooltipText: "Forget network"
|
tooltipText: "Forget network"
|
||||||
sizeRatio: 0.7
|
sizeRatio: 0.7
|
||||||
|
|
@ -384,10 +373,7 @@ NPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
NButton {
|
NButton {
|
||||||
visible: !modelData.connected && NetworkService.connectingTo !== modelData.ssid
|
visible: !modelData.connected && NetworkService.connectingTo !== modelData.ssid && passwordSsid !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
|
||||||
&& passwordSsid !== modelData.ssid
|
|
||||||
&& NetworkService.forgettingNetwork !== modelData.ssid
|
|
||||||
&& NetworkService.disconnectingFrom !== modelData.ssid
|
|
||||||
text: {
|
text: {
|
||||||
if (modelData.existing || modelData.cached)
|
if (modelData.existing || modelData.cached)
|
||||||
return "Connect"
|
return "Connect"
|
||||||
|
|
@ -422,8 +408,7 @@ NPanel {
|
||||||
|
|
||||||
// Password input
|
// Password input
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: passwordSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
|
visible: passwordSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid
|
||||||
&& NetworkService.forgettingNetwork !== modelData.ssid
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: passwordRow.implicitHeight + Style.marginS * scaling * 2
|
height: passwordRow.implicitHeight + Style.marginS * scaling * 2
|
||||||
color: Color.mSurfaceVariant
|
color: Color.mSurfaceVariant
|
||||||
|
|
@ -504,8 +489,7 @@ NPanel {
|
||||||
|
|
||||||
// Forget network
|
// Forget network
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: expandedSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
|
visible: expandedSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid
|
||||||
&& NetworkService.forgettingNetwork !== modelData.ssid
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: forgetRow.implicitHeight + Style.marginS * 2 * scaling
|
height: forgetRow.implicitHeight + Style.marginS * 2 * scaling
|
||||||
color: Color.mSurfaceVariant
|
color: Color.mSurfaceVariant
|
||||||
|
|
@ -561,8 +545,7 @@ NPanel {
|
||||||
|
|
||||||
// Empty state when no networks
|
// Empty state when no networks
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
visible: Settings.data.network.wifiEnabled && !NetworkService.scanning && Object.keys(
|
visible: Settings.data.network.wifiEnabled && !NetworkService.scanning && Object.keys(NetworkService.networks).length === 0
|
||||||
NetworkService.networks).length === 0
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: Style.marginL * scaling
|
spacing: Style.marginL * scaling
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,7 @@ Singleton {
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
parseAllUpdatesOutput(allUpdatesOutput, text)
|
parseAllUpdatesOutput(allUpdatesOutput, text)
|
||||||
Logger.log("ArchUpdater", "found", repoPackages.length, "repo package(s) and", aurPackages.length,
|
Logger.log("ArchUpdater", "found", repoPackages.length, "repo package(s) and", aurPackages.length, "AUR package(s) to upgrade")
|
||||||
"AUR package(s) to upgrade")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,7 @@ Singleton {
|
||||||
|
|
||||||
var name = (device.name || device.deviceName || "").toLowerCase()
|
var name = (device.name || device.deviceName || "").toLowerCase()
|
||||||
var icon = (device.icon || "").toLowerCase()
|
var icon = (device.icon || "").toLowerCase()
|
||||||
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod")
|
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod") || name.includes("headset") || name.includes("arctis")) {
|
||||||
|| name.includes("headset") || name.includes("arctis")) {
|
|
||||||
return "bt-device-headphones"
|
return "bt-device-headphones"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,8 +101,7 @@ Singleton {
|
||||||
if (icon.includes("keyboard") || name.includes("keyboard")) {
|
if (icon.includes("keyboard") || name.includes("keyboard")) {
|
||||||
return "bt-device-keyboard"
|
return "bt-device-keyboard"
|
||||||
}
|
}
|
||||||
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android")
|
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android") || name.includes("samsung")) {
|
||||||
|| name.includes("samsung")) {
|
|
||||||
return "bt-device-phone"
|
return "bt-device-phone"
|
||||||
}
|
}
|
||||||
if (icon.includes("watch") || name.includes("watch")) {
|
if (icon.includes("watch") || name.includes("watch")) {
|
||||||
|
|
@ -204,8 +202,7 @@ Singleton {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return device.pairing || device.state === BluetoothDeviceState.Disconnecting
|
return device.pairing || device.state === BluetoothDeviceState.Disconnecting || device.state === BluetoothDeviceState.Connecting
|
||||||
|| device.state === BluetoothDeviceState.Connecting
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectDeviceWithTrust(device) {
|
function connectDeviceWithTrust(device) {
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,7 @@ Singleton {
|
||||||
var ddcModel = ddcModelMatc ? ddcModelMatc.length > 0 : false
|
var ddcModel = ddcModelMatc ? ddcModelMatc.length > 0 : false
|
||||||
var model = modelMatch ? modelMatch[1] : "Unknown"
|
var model = modelMatch ? modelMatch[1] : "Unknown"
|
||||||
var bus = busMatch ? busMatch[1] : "Unknown"
|
var bus = busMatch ? busMatch[1] : "Unknown"
|
||||||
Logger.log("Detected DDC Monitor:", model, "on bus", bus, "is DDC:",
|
Logger.log("Detected DDC Monitor:", model, "on bus", bus, "is DDC:", !ddcModel)
|
||||||
!ddcModel)
|
|
||||||
return {
|
return {
|
||||||
"model": model,
|
"model": model,
|
||||||
"busNum": bus,
|
"busNum": bus,
|
||||||
|
|
@ -261,9 +260,7 @@ Singleton {
|
||||||
} else {
|
} else {
|
||||||
// Internal backlight - find the first available backlight device and get its info
|
// Internal backlight - find the first available backlight device and get its info
|
||||||
// This now returns: device_path, current_brightness, max_brightness (on separate lines)
|
// This now returns: device_path, current_brightness, max_brightness (on separate lines)
|
||||||
initProc.command = ["sh", "-c", "for dev in /sys/class/backlight/*; do "
|
initProc.command = ["sh", "-c", "for dev in /sys/class/backlight/*; do " + " if [ -f \"$dev/brightness\" ] && [ -f \"$dev/max_brightness\" ]; then " + " echo \"$dev\"; " + " cat \"$dev/brightness\"; " + " cat \"$dev/max_brightness\"; " + " break; " + " fi; " + "done"]
|
||||||
+ " if [ -f \"$dev/brightness\" ] && [ -f \"$dev/max_brightness\" ]; then " + " echo \"$dev\"; "
|
|
||||||
+ " cat \"$dev/brightness\"; " + " cat \"$dev/max_brightness\"; " + " break; " + " fi; " + "done"]
|
|
||||||
}
|
}
|
||||||
initProc.running = true
|
initProc.running = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,7 @@ Singleton {
|
||||||
root.cliphistAvailable = false
|
root.cliphistAvailable = false
|
||||||
// Show toast notification if feature is enabled but cliphist is missing
|
// Show toast notification if feature is enabled but cliphist is missing
|
||||||
if (Settings.data.appLauncher.enableClipboardHistory) {
|
if (Settings.data.appLauncher.enableClipboardHistory) {
|
||||||
ToastService.showWarning(
|
ToastService.showWarning("Clipboard History Unavailable", "The 'cliphist' application is not installed. Please install it to use clipboard history features.", false, 6000)
|
||||||
"Clipboard History Unavailable",
|
|
||||||
"The 'cliphist' application is not installed. Please install it to use clipboard history features.",
|
|
||||||
false, 6000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,21 +58,16 @@ Singleton {
|
||||||
|
|
||||||
if (monospaceFonts.count === 0) {
|
if (monospaceFonts.count === 0) {
|
||||||
Logger.log("Font", "No monospace fonts detected, adding fallbacks")
|
Logger.log("Font", "No monospace fonts detected, adding fallbacks")
|
||||||
addFallbackFonts(
|
addFallbackFonts(monospaceFonts, ["DejaVu Sans Mono", "Liberation Mono", "Courier New", "Courier", "Monaco", "Consolas", "Lucida Console", "Monaco", "Andale Mono"])
|
||||||
monospaceFonts,
|
|
||||||
["DejaVu Sans Mono", "Liberation Mono", "Courier New", "Courier", "Monaco", "Consolas", "Lucida Console", "Monaco", "Andale Mono"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayFonts.count === 0) {
|
if (displayFonts.count === 0) {
|
||||||
Logger.log("Font", "No display fonts detected, adding fallbacks")
|
Logger.log("Font", "No display fonts detected, adding fallbacks")
|
||||||
addFallbackFonts(
|
addFallbackFonts(displayFonts, ["Inter", "Roboto", "Open Sans", "Arial", "Helvetica", "Verdana", "Segoe UI", "SF Pro Display", "Ubuntu", "Noto Sans"])
|
||||||
displayFonts,
|
|
||||||
["Inter", "Roboto", "Open Sans", "Arial", "Helvetica", "Verdana", "Segoe UI", "SF Pro Display", "Ubuntu", "Noto Sans"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fontsLoaded = true
|
fontsLoaded = true
|
||||||
Logger.log("Font", "Loaded", availableFonts.count, "fonts:", monospaceFonts.count, "monospace,",
|
Logger.log("Font", "Loaded", availableFonts.count, "fonts:", monospaceFonts.count, "monospace,", displayFonts.count, "display")
|
||||||
displayFonts.count, "display")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMonospaceFont(fontName) {
|
function isMonospaceFont(fontName) {
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,7 @@ Singleton {
|
||||||
Logger.log("GitHub", "Raw contributors response length:", response ? response.length : 0)
|
Logger.log("GitHub", "Raw contributors response length:", response ? response.length : 0)
|
||||||
if (response && response.trim()) {
|
if (response && response.trim()) {
|
||||||
const data = JSON.parse(response)
|
const data = JSON.parse(response)
|
||||||
Logger.log("GitHub", "Parsed contributors data type:", typeof data, "length:",
|
Logger.log("GitHub", "Parsed contributors data type:", typeof data, "length:", Array.isArray(data) ? data.length : "not array")
|
||||||
Array.isArray(data) ? data.length : "not array")
|
|
||||||
root.data.contributors = data || []
|
root.data.contributors = data || []
|
||||||
root.contributors = root.data.contributors
|
root.contributors = root.data.contributors
|
||||||
Logger.log("GitHub", "Contributors fetched from GitHub:", root.contributors.length)
|
Logger.log("GitHub", "Contributors fetched from GitHub:", root.contributors.length)
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,7 @@ Singleton {
|
||||||
|
|
||||||
// Systemd inhibition using systemd-inhibit
|
// Systemd inhibition using systemd-inhibit
|
||||||
function startSystemdInhibition() {
|
function startSystemdInhibition() {
|
||||||
inhibitorProcess.command = ["systemd-inhibit", "--what=idle:sleep:handle-lid-switch", "--why="
|
inhibitorProcess.command = ["systemd-inhibit", "--what=idle:sleep:handle-lid-switch", "--why=" + reason, "--mode=block", "sleep", "infinity"]
|
||||||
+ reason, "--mode=block", "sleep", "infinity"]
|
|
||||||
inhibitorProcess.running = true
|
inhibitorProcess.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,8 +216,7 @@ Singleton {
|
||||||
// Try detection methods in order of preference
|
// Try detection methods in order of preference
|
||||||
if (Qt.platform.os === "linux") {
|
if (Qt.platform.os === "linux") {
|
||||||
// Check if we're in X11 or Wayland
|
// Check if we're in X11 or Wayland
|
||||||
const sessionType = Qt.application.arguments.find(arg => arg.includes("QT_QPA_PLATFORM"))
|
const sessionType = Qt.application.arguments.find(arg => arg.includes("QT_QPA_PLATFORM")) || process.env.XDG_SESSION_TYPE
|
||||||
|| process.env.XDG_SESSION_TYPE
|
|
||||||
|
|
||||||
if (sessionType && sessionType.includes("xcb") || process.env.DISPLAY) {
|
if (sessionType && sessionType.includes("xcb") || process.env.DISPLAY) {
|
||||||
// X11 system
|
// X11 system
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,7 @@ Singleton {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((adapter.weatherLastFetch === "") || (adapter.weather === null) || (adapter.latitude === "")
|
if ((adapter.weatherLastFetch === "") || (adapter.weather === null) || (adapter.latitude === "") || (adapter.longitude === "") || (adapter.name !== Settings.data.location.name) || (Time.timestamp >= adapter.weatherLastFetch + weatherUpdateFrequency)) {
|
||||||
|| (adapter.longitude === "") || (adapter.name !== Settings.data.location.name)
|
|
||||||
|| (Time.timestamp >= adapter.weatherLastFetch + weatherUpdateFrequency)) {
|
|
||||||
getFreshWeather()
|
getFreshWeather()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,8 +159,7 @@ Singleton {
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
function _geocodeLocation(locationName, callback, errorCallback) {
|
function _geocodeLocation(locationName, callback, errorCallback) {
|
||||||
Logger.log("Location", "Geocoding location name")
|
Logger.log("Location", "Geocoding location name")
|
||||||
var geoUrl = "https://assets.noctalia.dev/geocode.php?city=" + encodeURIComponent(
|
var geoUrl = "https://assets.noctalia.dev/geocode.php?city=" + encodeURIComponent(locationName) + "&language=en&format=json"
|
||||||
locationName) + "&language=en&format=json"
|
|
||||||
var xhr = new XMLHttpRequest()
|
var xhr = new XMLHttpRequest()
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
|
@ -189,8 +186,7 @@ Singleton {
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
function _fetchWeather(latitude, longitude, errorCallback) {
|
function _fetchWeather(latitude, longitude, errorCallback) {
|
||||||
Logger.log("Location", "Fetching weather from api.open-meteo.com")
|
Logger.log("Location", "Fetching weather from api.open-meteo.com")
|
||||||
var url = "https://api.open-meteo.com/v1/forecast?latitude=" + latitude + "&longitude=" + longitude
|
var url = "https://api.open-meteo.com/v1/forecast?latitude=" + latitude + "&longitude=" + longitude + "¤t_weather=true¤t=relativehumidity_2m,surface_pressure&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=auto"
|
||||||
+ "¤t_weather=true¤t=relativehumidity_2m,surface_pressure&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=auto"
|
|
||||||
var xhr = new XMLHttpRequest()
|
var xhr = new XMLHttpRequest()
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,8 @@ Singleton {
|
||||||
var extraUser = (Settings.configDir + "matugen.d").replace(/'/g, "'\\''")
|
var extraUser = (Settings.configDir + "matugen.d").replace(/'/g, "'\\''")
|
||||||
|
|
||||||
// Build the main script
|
// Build the main script
|
||||||
var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + "for d in '" + extraRepo + "' '" + extraUser
|
var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + "for d in '" + extraRepo + "' '" + extraUser + "'; do\n" + " if [ -d \"$d\" ]; then\n" + " for f in \"$d\"/*.toml; do\n" + " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '" + pathEsc + "'\n" + " done\n" + " fi\n" + "done\n" + "matugen image '"
|
||||||
+ "'; do\n" + " if [ -d \"$d\" ]; then\n"
|
+ wp + "' --config '" + pathEsc + "' --mode " + mode
|
||||||
+ " for f in \"$d\"/*.toml; do\n" + " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '"
|
|
||||||
+ pathEsc + "'\n" + " done\n" + " fi\n" + "done\n" + "matugen image '" + wp + "' --config '" + pathEsc + "' --mode " + mode
|
|
||||||
|
|
||||||
// Add user config execution if enabled
|
// Add user config execution if enabled
|
||||||
if (Settings.data.matugen.enableUserTemplates) {
|
if (Settings.data.matugen.enableUserTemplates) {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ Singleton {
|
||||||
property real currentPosition: 0
|
property real currentPosition: 0
|
||||||
property bool isSeeking: false
|
property bool isSeeking: false
|
||||||
property int selectedPlayerIndex: 0
|
property int selectedPlayerIndex: 0
|
||||||
property bool isPlaying: currentPlayer ? (currentPlayer.playbackState === MprisPlaybackState.Playing
|
property bool isPlaying: currentPlayer ? (currentPlayer.playbackState === MprisPlaybackState.Playing || currentPlayer.isPlaying) : false
|
||||||
|| currentPlayer.isPlaying) : false
|
|
||||||
property string trackTitle: currentPlayer ? (currentPlayer.trackTitle || "") : ""
|
property string trackTitle: currentPlayer ? (currentPlayer.trackTitle || "") : ""
|
||||||
property string trackArtist: currentPlayer ? (currentPlayer.trackArtist || "") : ""
|
property string trackArtist: currentPlayer ? (currentPlayer.trackArtist || "") : ""
|
||||||
property string trackAlbum: currentPlayer ? (currentPlayer.trackAlbum || "") : ""
|
property string trackAlbum: currentPlayer ? (currentPlayer.trackAlbum || "") : ""
|
||||||
|
|
@ -40,8 +39,7 @@ Singleton {
|
||||||
let controllablePlayers = []
|
let controllablePlayers = []
|
||||||
|
|
||||||
// Apply blacklist and controllable filter
|
// Apply blacklist and controllable filter
|
||||||
const blacklist = (Settings.data.audio
|
const blacklist = (Settings.data.audio && Settings.data.audio.mprisBlacklist) ? Settings.data.audio.mprisBlacklist : []
|
||||||
&& Settings.data.audio.mprisBlacklist) ? Settings.data.audio.mprisBlacklist : []
|
|
||||||
for (var i = 0; i < allPlayers.length; i++) {
|
for (var i = 0; i < allPlayers.length; i++) {
|
||||||
let player = allPlayers[i]
|
let player = allPlayers[i]
|
||||||
if (!player)
|
if (!player)
|
||||||
|
|
@ -52,8 +50,7 @@ Singleton {
|
||||||
const idKey = identity.toLowerCase()
|
const idKey = identity.toLowerCase()
|
||||||
const match = blacklist.find(b => {
|
const match = blacklist.find(b => {
|
||||||
const s = String(b || "").toLowerCase()
|
const s = String(b || "").toLowerCase()
|
||||||
return s && (idKey.includes(s) || busName.toLowerCase().includes(s)
|
return s && (idKey.includes(s) || busName.toLowerCase().includes(s) || desktop.toLowerCase().includes(s))
|
||||||
|| desktop.toLowerCase().includes(s))
|
|
||||||
})
|
})
|
||||||
if (match)
|
if (match)
|
||||||
continue
|
continue
|
||||||
|
|
@ -159,12 +156,10 @@ Singleton {
|
||||||
Timer {
|
Timer {
|
||||||
id: positionTimer
|
id: positionTimer
|
||||||
interval: 1000
|
interval: 1000
|
||||||
running: currentPlayer && !root.isSeeking && currentPlayer.isPlaying && currentPlayer.length > 0
|
running: currentPlayer && !root.isSeeking && currentPlayer.isPlaying && currentPlayer.length > 0 && currentPlayer.playbackState === MprisPlaybackState.Playing
|
||||||
&& currentPlayer.playbackState === MprisPlaybackState.Playing
|
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (currentPlayer && !root.isSeeking && currentPlayer.isPlaying
|
if (currentPlayer && !root.isSeeking && currentPlayer.isPlaying && currentPlayer.playbackState === MprisPlaybackState.Playing) {
|
||||||
&& currentPlayer.playbackState === MprisPlaybackState.Playing) {
|
|
||||||
currentPosition = currentPlayer.position
|
currentPosition = currentPlayer.position
|
||||||
} else {
|
} else {
|
||||||
running = false
|
running = false
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,7 @@ Singleton {
|
||||||
property int maxHistory: 100
|
property int maxHistory: 100
|
||||||
|
|
||||||
// Cached history file path
|
// Cached history file path
|
||||||
property string historyFile: Quickshell.env("NOCTALIA_NOTIF_HISTORY_FILE")
|
property string historyFile: Quickshell.env("NOCTALIA_NOTIF_HISTORY_FILE") || (Settings.cacheDir + "notifications.json")
|
||||||
|| (Settings.cacheDir + "notifications.json")
|
|
||||||
|
|
||||||
// Persisted storage for history
|
// Persisted storage for history
|
||||||
property FileView historyFileView: FileView {
|
property FileView historyFileView: FileView {
|
||||||
|
|
@ -280,9 +279,7 @@ Singleton {
|
||||||
"appIcon": n.appIcon,
|
"appIcon": n.appIcon,
|
||||||
"urgency": n.urgency,
|
"urgency": n.urgency,
|
||||||
"timestamp"// Always persist in milliseconds
|
"timestamp"// Always persist in milliseconds
|
||||||
: (n.timestamp instanceof Date) ? n.timestamp.getTime(
|
: (n.timestamp instanceof Date) ? n.timestamp.getTime() : (typeof n.timestamp === "number" && n.timestamp < 1e12 ? n.timestamp * 1000 : n.timestamp)
|
||||||
) : (typeof n.timestamp === "number"
|
|
||||||
&& n.timestamp < 1e12 ? n.timestamp * 1000 : n.timestamp)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
historyAdapter.history = arr
|
historyAdapter.history = arr
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,7 @@ Singleton {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Quickshell.execDetached(
|
Quickshell.execDetached(["sh", "-c", "pkill -SIGINT -f 'gpu-screen-recorder' || pkill -SIGINT -f 'com.dec05eba.gpu_screen_recorder'"])
|
||||||
["sh", "-c", "pkill -SIGINT -f 'gpu-screen-recorder' || pkill -SIGINT -f 'com.dec05eba.gpu_screen_recorder'"])
|
|
||||||
|
|
||||||
isRecording = false
|
isRecording = false
|
||||||
isPending = false
|
isPending = false
|
||||||
|
|
@ -152,8 +151,7 @@ Singleton {
|
||||||
running: false
|
running: false
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Quickshell.execDetached(
|
Quickshell.execDetached(["sh", "-c", "pkill -9 -f 'gpu-screen-recorder' 2>/dev/null || pkill -9 -f 'com.dec05eba.gpu_screen_recorder' 2>/dev/null || true"])
|
||||||
["sh", "-c", "pkill -9 -f 'gpu-screen-recorder' 2>/dev/null || pkill -9 -f 'com.dec05eba.gpu_screen_recorder' 2>/dev/null || true"])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,8 +97,7 @@ Singleton {
|
||||||
// All transition keys but filter out "none" and "random" so we are left with the real transitions
|
// All transition keys but filter out "none" and "random" so we are left with the real transitions
|
||||||
readonly property var allTransitions: Array.from({
|
readonly property var allTransitions: Array.from({
|
||||||
"length": transitionsModel.count
|
"length": transitionsModel.count
|
||||||
}, (_, i) => transitionsModel.get(i).key).filter(
|
}, (_, i) => transitionsModel.get(i).key).filter(key => key !== "random" && key != "none")
|
||||||
key => key !== "random" && key != "none")
|
|
||||||
|
|
||||||
property var wallpaperLists: ({})
|
property var wallpaperLists: ({})
|
||||||
property int scanningCount: 0
|
property int scanningCount: 0
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ Rectangle {
|
||||||
|
|
||||||
// Dimensions
|
// Dimensions
|
||||||
implicitWidth: customWidth > 0 ? customWidth : contentRow.implicitWidth + (Style.marginL * 2 * scaling)
|
implicitWidth: customWidth > 0 ? customWidth : contentRow.implicitWidth + (Style.marginL * 2 * scaling)
|
||||||
implicitHeight: customHeight > 0 ? customHeight : Math.max(Style.baseWidgetSize * scaling,
|
implicitHeight: customHeight > 0 ? customHeight : Math.max(Style.baseWidgetSize * scaling, contentRow.implicitHeight + (Style.marginM * scaling))
|
||||||
contentRow.implicitHeight + (Style.marginM * scaling))
|
|
||||||
|
|
||||||
// Appearance
|
// Appearance
|
||||||
radius: Style.radiusS * scaling
|
radius: Style.radiusS * scaling
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,7 @@ Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: "RGB(" + Math.round(root.selectedColor.r * 255) + ", " + Math.round(
|
text: "RGB(" + Math.round(root.selectedColor.r * 255) + ", " + Math.round(root.selectedColor.g * 255) + ", " + Math.round(root.selectedColor.b * 255) + ")"
|
||||||
root.selectedColor.g * 255) + ", " + Math.round(root.selectedColor.b * 255) + ")"
|
|
||||||
font.family: Settings.data.ui.fontFixed
|
font.family: Settings.data.ui.fontFixed
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
font.pointSize: Style.fontSizeM * scaling
|
||||||
color: root.selectedColor.r + root.selectedColor.g + root.selectedColor.b > 1.5 ? "#000000" : "#FFFFFF"
|
color: root.selectedColor.r + root.selectedColor.g + root.selectedColor.b > 1.5 ? "#000000" : "#FFFFFF"
|
||||||
|
|
@ -252,8 +251,7 @@ Popup {
|
||||||
value: Math.round(root.selectedColor.r * 255)
|
value: Math.round(root.selectedColor.r * 255)
|
||||||
onMoved: {
|
onMoved: {
|
||||||
root.selectedColor = Qt.rgba(value / 255, root.selectedColor.g, root.selectedColor.b, 1)
|
root.selectedColor = Qt.rgba(value / 255, root.selectedColor.g, root.selectedColor.b, 1)
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
root.currentHue = hsv[0]
|
root.currentHue = hsv[0]
|
||||||
root.currentSaturation = hsv[1]
|
root.currentSaturation = hsv[1]
|
||||||
}
|
}
|
||||||
|
|
@ -285,8 +283,7 @@ Popup {
|
||||||
onMoved: {
|
onMoved: {
|
||||||
root.selectedColor = Qt.rgba(root.selectedColor.r, value / 255, root.selectedColor.b, 1)
|
root.selectedColor = Qt.rgba(root.selectedColor.r, value / 255, root.selectedColor.b, 1)
|
||||||
// Update stored hue and saturation when RGB changes
|
// Update stored hue and saturation when RGB changes
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
root.currentHue = hsv[0]
|
root.currentHue = hsv[0]
|
||||||
root.currentSaturation = hsv[1]
|
root.currentSaturation = hsv[1]
|
||||||
}
|
}
|
||||||
|
|
@ -318,8 +315,7 @@ Popup {
|
||||||
onMoved: {
|
onMoved: {
|
||||||
root.selectedColor = Qt.rgba(root.selectedColor.r, root.selectedColor.g, value / 255, 1)
|
root.selectedColor = Qt.rgba(root.selectedColor.r, root.selectedColor.g, value / 255, 1)
|
||||||
// Update stored hue and saturation when RGB changes
|
// Update stored hue and saturation when RGB changes
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
root.currentHue = hsv[0]
|
root.currentHue = hsv[0]
|
||||||
root.currentSaturation = hsv[1]
|
root.currentSaturation = hsv[1]
|
||||||
}
|
}
|
||||||
|
|
@ -348,8 +344,7 @@ Popup {
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
value: {
|
value: {
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
return hsv[2]
|
return hsv[2]
|
||||||
}
|
}
|
||||||
onMoved: {
|
onMoved: {
|
||||||
|
|
@ -357,8 +352,7 @@ Popup {
|
||||||
var saturation = root.currentSaturation
|
var saturation = root.currentSaturation
|
||||||
|
|
||||||
if (hue === 0 && saturation === 0) {
|
if (hue === 0 && saturation === 0) {
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
hue = hsv[0]
|
hue = hsv[0]
|
||||||
saturation = hsv[1]
|
saturation = hsv[1]
|
||||||
root.currentHue = hue
|
root.currentHue = hue
|
||||||
|
|
@ -416,8 +410,7 @@ Popup {
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.selectedColor = modelData
|
root.selectedColor = modelData
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
root.currentHue = hsv[0]
|
root.currentHue = hsv[0]
|
||||||
root.currentSaturation = hsv[1]
|
root.currentSaturation = hsv[1]
|
||||||
}
|
}
|
||||||
|
|
@ -459,16 +452,14 @@ Popup {
|
||||||
radius: Style.radiusXXS * scaling
|
radius: Style.radiusXXS * scaling
|
||||||
color: modelData
|
color: modelData
|
||||||
border.color: root.selectedColor === modelData ? Color.mPrimary : Color.mOutline
|
border.color: root.selectedColor === modelData ? Color.mPrimary : Color.mOutline
|
||||||
border.width: Math.max(
|
border.width: Math.max(1, root.selectedColor === modelData ? Style.borderM * scaling : Style.borderS * scaling)
|
||||||
1, root.selectedColor === modelData ? Style.borderM * scaling : Style.borderS * scaling)
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.selectedColor = modelData
|
root.selectedColor = modelData
|
||||||
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255,
|
var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255)
|
||||||
root.selectedColor.b * 255)
|
|
||||||
root.currentHue = hsv[0]
|
root.currentHue = hsv[0]
|
||||||
root.currentSaturation = hsv[1]
|
root.currentSaturation = hsv[1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,8 @@ RowLayout {
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
font.pointSize: Style.fontSizeM * scaling
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: (combo.currentIndex >= 0
|
color: (combo.currentIndex >= 0 && combo.currentIndex < root.model.count) ? Color.mOnSurface : Color.mOnSurfaceVariant
|
||||||
&& combo.currentIndex < root.model.count) ? Color.mOnSurface : Color.mOnSurfaceVariant
|
text: (combo.currentIndex >= 0 && combo.currentIndex < root.model.count) ? root.model.get(combo.currentIndex).name : root.placeholder
|
||||||
text: (combo.currentIndex >= 0
|
|
||||||
&& combo.currentIndex < root.model.count) ? root.model.get(combo.currentIndex).name : root.placeholder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
indicator: NIcon {
|
indicator: NIcon {
|
||||||
|
|
|
||||||
|
|
@ -142,8 +142,7 @@ Loader {
|
||||||
property real scaling: ScalingService.getScreenScale(screen)
|
property real scaling: ScalingService.getScreenScale(screen)
|
||||||
readonly property real barHeight: Math.round(Style.barHeight * scaling)
|
readonly property real barHeight: Math.round(Style.barHeight * scaling)
|
||||||
readonly property bool barAtBottom: Settings.data.bar.position === "bottom"
|
readonly property bool barAtBottom: Settings.data.bar.position === "bottom"
|
||||||
readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name)
|
readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name) || (Settings.data.bar.monitors.length === 0))
|
||||||
|| (Settings.data.bar.monitors.length === 0))
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ScalingService
|
target: ScalingService
|
||||||
|
|
@ -169,8 +168,7 @@ Loader {
|
||||||
visible: true
|
visible: true
|
||||||
|
|
||||||
// Dim desktop if required
|
// Dim desktop if required
|
||||||
color: (root.active && !root.isClosing
|
color: (root.active && !root.isClosing && Settings.data.general.dimDesktop) ? Qt.alpha(Color.mShadow, Style.opacityHeavy) : Color.transparent
|
||||||
&& Settings.data.general.dimDesktop) ? Qt.alpha(Color.mShadow, Style.opacityHeavy) : Color.transparent
|
|
||||||
|
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
WlrLayershell.namespace: "noctalia-panel"
|
WlrLayershell.namespace: "noctalia-panel"
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ T.ScrollView {
|
||||||
property int horizontalPolicy: ScrollBar.AsNeeded
|
property int horizontalPolicy: ScrollBar.AsNeeded
|
||||||
|
|
||||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
|
||||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding)
|
||||||
contentHeight + topPadding + bottomPadding)
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
ScrollBar.vertical: ScrollBar {
|
||||||
parent: root
|
parent: root
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ Slider {
|
||||||
height: knobDiameter + cutoutExtra
|
height: knobDiameter + cutoutExtra
|
||||||
radius: width / 2
|
radius: width / 2
|
||||||
color: root.cutoutColor !== undefined ? root.cutoutColor : Color.mSurface
|
color: root.cutoutColor !== undefined ? root.cutoutColor : Color.mSurface
|
||||||
x: Math.max(0, Math.min(parent.width - width,
|
x: Math.max(0, Math.min(parent.width - width, root.visualPosition * (parent.width - root.knobDiameter) - cutoutExtra / 2))
|
||||||
root.visualPosition * (parent.width - root.knobDiameter) - cutoutExtra / 2))
|
|
||||||
y: (parent.height - height) / 2
|
y: (parent.height - height) / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue