mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 03:28:28 -04:00
qs: large sweep of dead code removals
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
function clearImageCache() {
|
||||
Quickshell.execDetached(["rm", "-rf", Paths.stringify(Paths.imagecache)]);
|
||||
Paths.mkdir(Paths.imagecache);
|
||||
}
|
||||
|
||||
function clearOldCache(ageInMinutes) {
|
||||
Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", "*.png", "-mmin", `+${ageInMinutes}`, "-delete"]);
|
||||
}
|
||||
|
||||
function clearCacheForSize(size) {
|
||||
Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", `*@${size}x${size}.png`, "-delete"]);
|
||||
}
|
||||
|
||||
function getCacheSize(callback) {
|
||||
Proc.runCommand("cache_size", ["du", "-sm", Paths.stringify(Paths.imagecache)], function (output, exitCode) {
|
||||
const sizeMB = parseInt(output.split("\t")[0]) || 0;
|
||||
callback(sizeMB);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -114,26 +114,6 @@ function withRevision(descriptor, revision) {
|
||||
return next;
|
||||
}
|
||||
|
||||
function withAnimationOffset(descriptor, x, y) {
|
||||
var next = normalize(descriptor);
|
||||
next.animationOffset = {
|
||||
"x": x === undefined ? next.animationOffset.x : _number(x, next.animationOffset.x),
|
||||
"y": y === undefined ? next.animationOffset.y : _number(y, next.animationOffset.y)
|
||||
};
|
||||
return next;
|
||||
}
|
||||
|
||||
function withBodyRect(descriptor, x, y, width, height) {
|
||||
var next = normalize(descriptor);
|
||||
next.bodyRect = {
|
||||
"x": x === undefined ? next.bodyRect.x : _number(x, next.bodyRect.x),
|
||||
"y": y === undefined ? next.bodyRect.y : _number(y, next.bodyRect.y),
|
||||
"width": width === undefined ? next.bodyRect.width : Math.max(0, _number(width, next.bodyRect.width)),
|
||||
"height": height === undefined ? next.bodyRect.height : Math.max(0, _number(height, next.bodyRect.height))
|
||||
};
|
||||
return next;
|
||||
}
|
||||
|
||||
function same(a, b, threshold) {
|
||||
if (!a || !b)
|
||||
return false;
|
||||
|
||||
@@ -162,21 +162,6 @@ function fillBounds(rect, side, seamOverlap, dpr) {
|
||||
};
|
||||
}
|
||||
|
||||
function clipEnvelope(rect, side, radii, seamOverlap, dpr) {
|
||||
var fill = fillBounds(rect, side, seamOverlap, dpr);
|
||||
var chrome = chromeBounds(fill, side, radii.start, radii.end, radii.farExtent, dpr);
|
||||
return {
|
||||
"x": chrome.x,
|
||||
"y": chrome.y,
|
||||
"width": chrome.width,
|
||||
"height": chrome.height,
|
||||
"bodyX": snap(fill.x - chrome.x, dpr),
|
||||
"bodyY": snap(fill.y - chrome.y, dpr),
|
||||
"bodyWidth": fill.width,
|
||||
"bodyHeight": fill.height
|
||||
};
|
||||
}
|
||||
|
||||
function blurRegions(descriptor, rect, radii, dpr) {
|
||||
var side = descriptor.barSide;
|
||||
var regions = [bodyRect(rect, dpr)];
|
||||
@@ -219,14 +204,3 @@ function unionBounds(rects, padding, dpr) {
|
||||
"height": Math.max(0, snap(maxY - minY + pad * 2, dpr))
|
||||
};
|
||||
}
|
||||
|
||||
function shadowSourceBounds(descriptor, rect, radii, padding, dpr) {
|
||||
return unionBounds(blurRegions(descriptor, rect, radii, dpr), padding, dpr);
|
||||
}
|
||||
|
||||
function stableEqual(a, b, dpr) {
|
||||
if (!a || !b)
|
||||
return false;
|
||||
var threshold = 0.5 / (dpr || 1);
|
||||
return Math.abs(a.x - b.x) < threshold && Math.abs(a.y - b.y) < threshold && Math.abs(a.width - b.width) < threshold && Math.abs(a.height - b.height) < threshold;
|
||||
}
|
||||
|
||||
@@ -44,16 +44,6 @@ function connectorX(barSide, baseX, bodyWidth, placement, spacing, radius) {
|
||||
return barSide === "left" ? s : s - w;
|
||||
}
|
||||
|
||||
function connectorY(barSide, baseY, bodyHeight, placement, spacing, radius) {
|
||||
var s = seamY(barSide, baseY, bodyHeight, placement);
|
||||
var h = connectorHeight(barSide, spacing, radius);
|
||||
if (barSide === "top")
|
||||
return s;
|
||||
if (barSide === "bottom")
|
||||
return s - h;
|
||||
return placement === "left" ? s - h : s;
|
||||
}
|
||||
|
||||
// Which corner of the connector's bounding rect hosts the concave arc that
|
||||
// carves into the body. Used for arc-sweep orientation.
|
||||
function arcCorner(barSide, placement) {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
.pragma library
|
||||
|
||||
function formatRate(bytesPerSec, gbDecimals) {
|
||||
if (bytesPerSec < 1024)
|
||||
return bytesPerSec.toFixed(0) + " B/s";
|
||||
if (bytesPerSec < 1024 * 1024)
|
||||
return (bytesPerSec / 1024).toFixed(1) + " KB/s";
|
||||
if (bytesPerSec < 1024 * 1024 * 1024)
|
||||
return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
|
||||
return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(gbDecimals ?? 2) + " GB/s";
|
||||
}
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (bytes < 1024)
|
||||
return bytes.toFixed(0) + "B";
|
||||
if (bytes < 1024 * 1024)
|
||||
return (bytes / 1024).toFixed(0) + "K";
|
||||
if (bytes < 1024 * 1024 * 1024)
|
||||
return (bytes / (1024 * 1024)).toFixed(1) + "M";
|
||||
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + "G";
|
||||
}
|
||||
|
||||
function formatIsoTime(isoString) {
|
||||
if (!isoString)
|
||||
return "";
|
||||
try {
|
||||
const date = new Date(isoString);
|
||||
if (isNaN(date.getTime()))
|
||||
return "";
|
||||
return date.toLocaleTimeString(Qt.locale(), "HH:mm");
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function formatRemaining(ms, zeroText, minText, hText, hmText) {
|
||||
if (ms <= 0)
|
||||
return zeroText;
|
||||
const totalMinutes = Math.ceil(ms / 60000);
|
||||
if (totalMinutes < 60)
|
||||
return minText.arg(totalMinutes);
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const mins = totalMinutes - hours * 60;
|
||||
if (mins === 0)
|
||||
return hText.arg(hours);
|
||||
return hmText.arg(hours).arg(mins);
|
||||
}
|
||||
|
||||
function pad2(n) {
|
||||
return n < 10 ? "0" + n : "" + n;
|
||||
}
|
||||
|
||||
function formatUntil(ts, use24h) {
|
||||
if (!ts)
|
||||
return "";
|
||||
const d = new Date(ts);
|
||||
const hours = d.getHours();
|
||||
const minutes = d.getMinutes();
|
||||
if (use24h)
|
||||
return pad2(hours) + ":" + pad2(minutes);
|
||||
const suffix = hours >= 12 ? "PM" : "AM";
|
||||
const h12 = ((hours + 11) % 12) + 1;
|
||||
return h12 + ":" + pad2(minutes) + " " + suffix;
|
||||
}
|
||||
|
||||
function addToHistory(arr, val, max) {
|
||||
const newArr = arr.slice();
|
||||
newArr.push(val);
|
||||
if (newArr.length > max)
|
||||
newArr.shift();
|
||||
return newArr;
|
||||
}
|
||||
@@ -1370,10 +1370,3 @@ function buildDmsAction(baseKey, args) {
|
||||
|
||||
return parts.join(" ");
|
||||
}
|
||||
|
||||
function getScreenshotOptions() {
|
||||
return [
|
||||
{ id: "write-to-disk", label: "Save to disk", type: "bool" },
|
||||
{ id: "show-pointer", label: "Show pointer", type: "bool" }
|
||||
];
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ Singleton {
|
||||
|
||||
readonly property url imagecache: `${cache}/imagecache`
|
||||
|
||||
property var iconResolver: null
|
||||
property var desktopIconResolver: null
|
||||
property var trashHandler: null
|
||||
|
||||
Component.onCompleted: mkdir(imagecache)
|
||||
|
||||
function stringify(path: url): string {
|
||||
@@ -88,7 +92,7 @@ Singleton {
|
||||
function themedIconPath(name: string): string {
|
||||
if (!name)
|
||||
return "";
|
||||
const themed = (typeof IconThemeService !== "undefined") ? IconThemeService.resolve(name) : "";
|
||||
const themed = iconResolver ? iconResolver(name) : "";
|
||||
if (themed)
|
||||
return themed;
|
||||
return Quickshell.iconPath(name, true);
|
||||
@@ -105,11 +109,15 @@ Singleton {
|
||||
return moddedId;
|
||||
return themedIconPath(moddedId);
|
||||
}
|
||||
return themedIconPath(iconName) || DesktopService.resolveIconPath(iconName);
|
||||
if (!desktopIconResolver)
|
||||
return themedIconPath(iconName);
|
||||
return themedIconPath(iconName) || desktopIconResolver(iconName);
|
||||
}
|
||||
|
||||
function trashPath(path: string, callback): void {
|
||||
TrashService.trashPath(path, callback);
|
||||
if (!trashHandler)
|
||||
return;
|
||||
trashHandler(path, callback);
|
||||
}
|
||||
|
||||
function copyPathToClipboard(path: string): void {
|
||||
@@ -125,7 +133,7 @@ Singleton {
|
||||
return toFileUrl(expandTilde(target));
|
||||
if (target.startsWith("file://"))
|
||||
return target;
|
||||
const themed = (typeof IconThemeService !== "undefined") ? IconThemeService.resolve(target) : "";
|
||||
const themed = iconResolver ? iconResolver(target) : "";
|
||||
if (themed)
|
||||
return themed;
|
||||
return "image://icon/" + target;
|
||||
@@ -148,7 +156,9 @@ Singleton {
|
||||
if (icon && icon !== "")
|
||||
return icon;
|
||||
|
||||
return DesktopService.resolveIconPath(appId);
|
||||
if (!desktopIconResolver)
|
||||
return "";
|
||||
return desktopIconResolver(appId);
|
||||
}
|
||||
|
||||
function getAppName(appId: string, desktopEntry: var): string {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
.pragma library
|
||||
|
||||
function findParentFlickable(item) {
|
||||
while (item) {
|
||||
if (item.hasOwnProperty("contentY") && item.hasOwnProperty("contentItem"))
|
||||
return item;
|
||||
item = item.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findSettings(item) {
|
||||
while (item) {
|
||||
if (item.saveValue !== undefined && item.loadValue !== undefined)
|
||||
return item;
|
||||
item = item.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function normalizePinList(value) {
|
||||
if (Array.isArray(value))
|
||||
return value.filter(v => v);
|
||||
if (typeof value === "string" && value.length > 0)
|
||||
return [value];
|
||||
return [];
|
||||
}
|
||||
@@ -16,6 +16,10 @@ Singleton {
|
||||
|
||||
readonly property int sessionConfigVersion: 3
|
||||
|
||||
signal loaded
|
||||
signal brightnessDisplayHintChanged(string deviceName)
|
||||
signal loadErrorOccurred(string file, string message)
|
||||
|
||||
property bool _parseError: false
|
||||
property bool _hasLoaded: false
|
||||
property bool _isReadOnly: false
|
||||
@@ -276,15 +280,14 @@ Singleton {
|
||||
if (typeof Theme !== "undefined")
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
|
||||
if (typeof WallpaperCyclingService !== "undefined")
|
||||
WallpaperCyclingService.updateCyclingState();
|
||||
loaded();
|
||||
|
||||
_checkSessionWritable();
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
const msg = e.message;
|
||||
log.error("Failed to parse session.json - file will not be overwritten.");
|
||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("session.json"), msg));
|
||||
Qt.callLater(() => loadErrorOccurred("session.json", msg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,13 +361,12 @@ Singleton {
|
||||
if (typeof Theme !== "undefined")
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
|
||||
if (typeof WallpaperCyclingService !== "undefined")
|
||||
WallpaperCyclingService.updateCyclingState();
|
||||
loaded();
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
const msg = e.message;
|
||||
log.error("Failed to parse session.json - file will not be overwritten.");
|
||||
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse %1").arg("session.json"), msg));
|
||||
Qt.callLater(() => loadErrorOccurred("session.json", msg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,11 +467,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setWallpaperPath(path) {
|
||||
wallpaperPath = path;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setWallpaper(imagePath) {
|
||||
wallpaperPath = imagePath;
|
||||
if (perModeWallpaper) {
|
||||
@@ -848,11 +845,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setNightModeLocationProvider(provider) {
|
||||
nightModeLocationProvider = provider;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setThemeModeAutoEnabled(enabled) {
|
||||
themeModeAutoEnabled = enabled;
|
||||
saveSettings();
|
||||
@@ -941,10 +933,6 @@ Singleton {
|
||||
setBarPinnedApps(currentPinned);
|
||||
}
|
||||
|
||||
function isBarPinnedApp(appId) {
|
||||
return appId && barPinnedApps.indexOf(appId) !== -1;
|
||||
}
|
||||
|
||||
function hideTrayId(trayId) {
|
||||
if (!trayId)
|
||||
return;
|
||||
@@ -1007,11 +995,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setLaunchPrefix(prefix) {
|
||||
launchPrefix = prefix;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setLastBrightnessDevice(device) {
|
||||
lastBrightnessDevice = device;
|
||||
saveSettings();
|
||||
@@ -1026,10 +1009,7 @@ Singleton {
|
||||
}
|
||||
brightnessExponentialDevices = newSettings;
|
||||
saveSettings();
|
||||
|
||||
if (typeof DisplayService !== "undefined") {
|
||||
DisplayService.updateDeviceBrightnessDisplay(deviceName);
|
||||
}
|
||||
brightnessDisplayHintChanged(deviceName);
|
||||
}
|
||||
|
||||
function getBrightnessExponential(deviceName) {
|
||||
@@ -1043,10 +1023,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getBrightnessUserSetValue(deviceName) {
|
||||
return brightnessUserSetValues[deviceName];
|
||||
}
|
||||
|
||||
function clearBrightnessUserSetValue(deviceName) {
|
||||
var newValues = Object.assign({}, brightnessUserSetValues);
|
||||
delete newValues[deviceName];
|
||||
@@ -1070,21 +1046,6 @@ Singleton {
|
||||
return value !== undefined ? value : 1.2;
|
||||
}
|
||||
|
||||
function setSelectedGpuIndex(index) {
|
||||
selectedGpuIndex = index;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setNvidiaGpuTempEnabled(enabled) {
|
||||
nvidiaGpuTempEnabled = enabled;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setNonNvidiaGpuTempEnabled(enabled) {
|
||||
nonNvidiaGpuTempEnabled = enabled;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setEnabledGpuPciIds(pciIds) {
|
||||
enabledGpuPciIds = pciIds;
|
||||
saveSettings();
|
||||
@@ -1200,15 +1161,6 @@ Singleton {
|
||||
return deviceMaxVolumes[nodeName] ?? 100;
|
||||
}
|
||||
|
||||
function removeDeviceMaxVolume(nodeName) {
|
||||
if (!nodeName)
|
||||
return;
|
||||
const updated = Object.assign({}, deviceMaxVolumes);
|
||||
delete updated[nodeName];
|
||||
deviceMaxVolumes = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function updateLocale() {
|
||||
if (!locale) {
|
||||
I18n._pickTranslation();
|
||||
@@ -1272,12 +1224,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function clearLauncherHistory() {
|
||||
launcherLastQuery = "";
|
||||
launcherSearchHistory = [];
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setAppDrawerLastMode(mode) {
|
||||
appDrawerLastMode = mode;
|
||||
saveSettings();
|
||||
@@ -1417,141 +1363,4 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "wallpaper"
|
||||
|
||||
function get(): string {
|
||||
if (root.perMonitorWallpaper) {
|
||||
return "ERROR: Per-monitor mode enabled. Use getFor(screenName) instead.";
|
||||
}
|
||||
return root.wallpaperPath || "";
|
||||
}
|
||||
|
||||
function set(path: string): string {
|
||||
if (root.perMonitorWallpaper) {
|
||||
return "ERROR: Per-monitor mode enabled. Use setFor(screenName, path) instead.";
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
return "ERROR: No path provided";
|
||||
}
|
||||
|
||||
var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path;
|
||||
|
||||
try {
|
||||
root.setWallpaper(absolutePath);
|
||||
return "SUCCESS: Wallpaper set to " + absolutePath;
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to set wallpaper: " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function clear(): string {
|
||||
root.setWallpaper("");
|
||||
root.setPerMonitorWallpaper(false);
|
||||
root.monitorWallpapers = {};
|
||||
root.saveSettings();
|
||||
return "SUCCESS: All wallpapers cleared";
|
||||
}
|
||||
|
||||
function next(): string {
|
||||
if (root.perMonitorWallpaper) {
|
||||
return "ERROR: Per-monitor mode enabled. Use nextFor(screenName) instead.";
|
||||
}
|
||||
|
||||
if (!root.wallpaperPath) {
|
||||
return "ERROR: No wallpaper set";
|
||||
}
|
||||
|
||||
try {
|
||||
WallpaperCyclingService.cycleNextManually();
|
||||
return "SUCCESS: Cycling to next wallpaper";
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to cycle wallpaper: " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function prev(): string {
|
||||
if (root.perMonitorWallpaper) {
|
||||
return "ERROR: Per-monitor mode enabled. Use prevFor(screenName) instead.";
|
||||
}
|
||||
|
||||
if (!root.wallpaperPath) {
|
||||
return "ERROR: No wallpaper set";
|
||||
}
|
||||
|
||||
try {
|
||||
WallpaperCyclingService.cyclePrevManually();
|
||||
return "SUCCESS: Cycling to previous wallpaper";
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to cycle wallpaper: " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function getFor(screenName: string): string {
|
||||
if (!screenName) {
|
||||
return "ERROR: No screen name provided";
|
||||
}
|
||||
return root.getMonitorWallpaper(screenName) || "";
|
||||
}
|
||||
|
||||
function setFor(screenName: string, path: string): string {
|
||||
if (!screenName) {
|
||||
return "ERROR: No screen name provided";
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
return "ERROR: No path provided";
|
||||
}
|
||||
|
||||
var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path;
|
||||
|
||||
try {
|
||||
if (!root.perMonitorWallpaper) {
|
||||
root.setPerMonitorWallpaper(true);
|
||||
}
|
||||
root.setMonitorWallpaper(screenName, absolutePath);
|
||||
return "SUCCESS: Wallpaper set for " + screenName + " to " + absolutePath;
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to set wallpaper for " + screenName + ": " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function nextFor(screenName: string): string {
|
||||
if (!screenName) {
|
||||
return "ERROR: No screen name provided";
|
||||
}
|
||||
|
||||
var currentWallpaper = root.getMonitorWallpaper(screenName);
|
||||
if (!currentWallpaper) {
|
||||
return "ERROR: No wallpaper set for " + screenName;
|
||||
}
|
||||
|
||||
try {
|
||||
WallpaperCyclingService.cycleNextForMonitor(screenName);
|
||||
return "SUCCESS: Cycling to next wallpaper for " + screenName;
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function prevFor(screenName: string): string {
|
||||
if (!screenName) {
|
||||
return "ERROR: No screen name provided";
|
||||
}
|
||||
|
||||
var currentWallpaper = root.getMonitorWallpaper(screenName);
|
||||
if (!currentWallpaper) {
|
||||
return "ERROR: No wallpaper set for " + screenName;
|
||||
}
|
||||
|
||||
try {
|
||||
WallpaperCyclingService.cyclePrevForMonitor(screenName);
|
||||
return "SUCCESS: Cycling to previous wallpaper for " + screenName;
|
||||
} catch (e) {
|
||||
return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,16 +712,23 @@ Singleton {
|
||||
property bool notepadUseCompositorGap: false
|
||||
property int notepadEdgeGap: 0
|
||||
|
||||
property string activeCompositor: ""
|
||||
|
||||
// Compositor layout gap when enabled and available, else the manual value.
|
||||
readonly property int notepadEffectiveEdgeGap: {
|
||||
if (notepadUseCompositorGap) {
|
||||
var g = -1;
|
||||
if (CompositorService.isNiri)
|
||||
switch (activeCompositor) {
|
||||
case "niri":
|
||||
g = niriLayoutGapsOverride;
|
||||
else if (CompositorService.isHyprland)
|
||||
break;
|
||||
case "hyprland":
|
||||
g = hyprlandLayoutGapsOverride;
|
||||
else if (CompositorService.isMango)
|
||||
break;
|
||||
case "mango":
|
||||
g = mangoLayoutGapsOverride;
|
||||
break;
|
||||
}
|
||||
if (g >= 0)
|
||||
return g;
|
||||
}
|
||||
@@ -1126,44 +1133,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getSystemMonitorVariants() {
|
||||
return systemMonitorVariants || [];
|
||||
}
|
||||
|
||||
function createSystemMonitorVariant(name, config) {
|
||||
const id = "sysmon_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
|
||||
const variant = {
|
||||
id: id,
|
||||
name: name,
|
||||
config: config || getDefaultSystemMonitorConfig()
|
||||
};
|
||||
const variants = JSON.parse(JSON.stringify(systemMonitorVariants || []));
|
||||
variants.push(variant);
|
||||
systemMonitorVariants = variants;
|
||||
saveSettings();
|
||||
return variant;
|
||||
}
|
||||
|
||||
function updateSystemMonitorVariant(variantId, updates) {
|
||||
const variants = JSON.parse(JSON.stringify(systemMonitorVariants || []));
|
||||
const idx = variants.findIndex(v => v.id === variantId);
|
||||
if (idx === -1)
|
||||
return;
|
||||
Object.assign(variants[idx], updates);
|
||||
systemMonitorVariants = variants;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function removeSystemMonitorVariant(variantId) {
|
||||
const variants = (systemMonitorVariants || []).filter(v => v.id !== variantId);
|
||||
systemMonitorVariants = variants;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getSystemMonitorVariant(variantId) {
|
||||
return (systemMonitorVariants || []).find(v => v.id === variantId) || null;
|
||||
}
|
||||
|
||||
function getDefaultSystemMonitorConfig() {
|
||||
return {
|
||||
showHeader: true,
|
||||
@@ -1304,70 +1273,6 @@ Singleton {
|
||||
return (desktopWidgetInstances || []).find(inst => inst.id === instanceId) || null;
|
||||
}
|
||||
|
||||
function getDesktopWidgetInstancesOfType(widgetType) {
|
||||
return (desktopWidgetInstances || []).filter(inst => inst.widgetType === widgetType);
|
||||
}
|
||||
|
||||
function getEnabledDesktopWidgetInstances() {
|
||||
return (desktopWidgetInstances || []).filter(inst => inst.enabled);
|
||||
}
|
||||
|
||||
function moveDesktopWidgetInstance(instanceId, direction) {
|
||||
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||
if (idx === -1)
|
||||
return false;
|
||||
const targetIdx = direction === "up" ? idx - 1 : idx + 1;
|
||||
if (targetIdx < 0 || targetIdx >= instances.length)
|
||||
return false;
|
||||
const temp = instances[idx];
|
||||
instances[idx] = instances[targetIdx];
|
||||
instances[targetIdx] = temp;
|
||||
desktopWidgetInstances = instances;
|
||||
saveSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
function reorderDesktopWidgetInstance(instanceId, newIndex) {
|
||||
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||
if (idx === -1 || newIndex < 0 || newIndex >= instances.length)
|
||||
return false;
|
||||
const [item] = instances.splice(idx, 1);
|
||||
instances.splice(newIndex, 0, item);
|
||||
desktopWidgetInstances = instances;
|
||||
saveSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
function reorderDesktopWidgetInstanceInGroup(instanceId, groupId, newIndexInGroup) {
|
||||
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||
const groups = desktopWidgetGroups || [];
|
||||
const groupMatches = inst => {
|
||||
if (groupId === null)
|
||||
return !inst.group || !groups.some(g => g.id === inst.group);
|
||||
return inst.group === groupId;
|
||||
};
|
||||
const groupInstances = instances.filter(groupMatches);
|
||||
const currentGroupIdx = groupInstances.findIndex(inst => inst.id === instanceId);
|
||||
if (currentGroupIdx === -1 || currentGroupIdx === newIndexInGroup)
|
||||
return false;
|
||||
if (newIndexInGroup < 0 || newIndexInGroup >= groupInstances.length)
|
||||
return false;
|
||||
const globalIdx = instances.findIndex(inst => inst.id === instanceId);
|
||||
if (globalIdx === -1)
|
||||
return false;
|
||||
const [item] = instances.splice(globalIdx, 1);
|
||||
const targetInstance = groupInstances[newIndexInGroup];
|
||||
let targetGlobalIdx = instances.findIndex(inst => inst.id === targetInstance.id);
|
||||
if (newIndexInGroup > currentGroupIdx)
|
||||
targetGlobalIdx++;
|
||||
instances.splice(targetGlobalIdx, 0, item);
|
||||
desktopWidgetInstances = instances;
|
||||
saveSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
function moveDesktopWidgetInstanceToGroup(instanceId, groupId, newIndexInGroup) {
|
||||
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||
const groups = desktopWidgetGroups || [];
|
||||
@@ -1433,22 +1338,14 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getDesktopWidgetGroup(groupId) {
|
||||
return (desktopWidgetGroups || []).find(g => g.id === groupId) || null;
|
||||
}
|
||||
|
||||
function getDesktopWidgetInstancesByGroup(groupId) {
|
||||
return (desktopWidgetInstances || []).filter(inst => inst.group === groupId);
|
||||
}
|
||||
|
||||
function getUngroupedDesktopWidgetInstances() {
|
||||
return (desktopWidgetInstances || []).filter(inst => !inst.group);
|
||||
}
|
||||
|
||||
signal forceDankBarLayoutRefresh
|
||||
signal forceDockLayoutRefresh
|
||||
signal widgetDataChanged
|
||||
signal workspaceIconsUpdated
|
||||
signal compositorLayoutRefreshNeeded(bool frame)
|
||||
signal compositorInputRefreshNeeded
|
||||
signal compositorCursorRefreshNeeded
|
||||
signal notificationPopupsInvalidated
|
||||
|
||||
function refreshAuthAvailability() {
|
||||
Processes.detectAuthCapabilities();
|
||||
@@ -1483,31 +1380,15 @@ Singleton {
|
||||
}
|
||||
|
||||
function updateCompositorLayout() {
|
||||
if (typeof CompositorService === "undefined")
|
||||
return;
|
||||
if (CompositorService.isNiri && typeof NiriService !== "undefined")
|
||||
NiriService.generateNiriLayoutConfig();
|
||||
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined")
|
||||
HyprlandService.generateLayoutConfig();
|
||||
if (CompositorService.isMango && typeof MangoService !== "undefined")
|
||||
MangoService.generateLayoutConfig();
|
||||
compositorLayoutRefreshNeeded(false);
|
||||
}
|
||||
|
||||
function updateCompositorInput() {
|
||||
if (typeof CompositorService === "undefined")
|
||||
return;
|
||||
if (CompositorService.isNiri && typeof NiriService !== "undefined")
|
||||
NiriService.generateNiriInputConfig();
|
||||
compositorInputRefreshNeeded();
|
||||
}
|
||||
|
||||
function updateFrameCompositorLayout() {
|
||||
// Generate before begin() so compositor readiness is already pending at transitionRequested
|
||||
if (typeof CompositorService !== "undefined") {
|
||||
if (CompositorService.isNiri && typeof NiriService !== "undefined")
|
||||
NiriService.generateNiriLayoutConfig(true);
|
||||
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined")
|
||||
HyprlandService.generateLayoutConfig(true);
|
||||
}
|
||||
compositorLayoutRefreshNeeded(true);
|
||||
FrameTransitionState.begin();
|
||||
}
|
||||
|
||||
@@ -2160,14 +2041,6 @@ Singleton {
|
||||
return showSeconds ? "h:mm:ss AP" : "h:mm AP";
|
||||
}
|
||||
|
||||
function getEffectiveClockDateFormat() {
|
||||
return clockDateFormat && clockDateFormat.length > 0 ? clockDateFormat : "ddd d";
|
||||
}
|
||||
|
||||
function getEffectiveLockDateFormat() {
|
||||
return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat;
|
||||
}
|
||||
|
||||
function initializeListModels() {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (defaultBar) {
|
||||
@@ -2180,39 +2053,6 @@ Singleton {
|
||||
widgetDataChanged();
|
||||
}
|
||||
|
||||
function hasNamedWorkspaces() {
|
||||
if (typeof NiriService === "undefined" || !CompositorService.isNiri)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||
var ws = NiriService.allWorkspaces[i];
|
||||
if (ws.name && ws.name.trim() !== "")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNamedWorkspaces() {
|
||||
var namedWorkspaces = [];
|
||||
if (typeof NiriService === "undefined" || !CompositorService.isNiri)
|
||||
return namedWorkspaces;
|
||||
|
||||
for (const ws of NiriService.allWorkspaces) {
|
||||
if (ws.name && ws.name.trim() !== "") {
|
||||
namedWorkspaces.push(ws.name);
|
||||
}
|
||||
}
|
||||
return namedWorkspaces;
|
||||
}
|
||||
|
||||
function getPopupYPosition(barHeight) {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
const gothOffset = defaultBar?.gothCornersEnabled ? Theme.cornerRadius : 0;
|
||||
const spacing = defaultBar?.spacing ?? 4;
|
||||
const bottomGap = defaultBar?.bottomGap ?? 0;
|
||||
return barHeight + spacing + bottomGap - gothOffset + Theme.popupDistance;
|
||||
}
|
||||
|
||||
function getPopupTriggerPosition(pos, screen, barThickness, widgetWidth, barSpacing, barPosition, barConfig) {
|
||||
const relativeX = pos.x;
|
||||
const relativeY = pos.y;
|
||||
@@ -2506,51 +2346,10 @@ Singleton {
|
||||
updateBarConfigs();
|
||||
|
||||
if (positionChanged) {
|
||||
NotificationService.dismissAllPopups();
|
||||
notificationPopupsInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
function checkBarCollisions(barId) {
|
||||
const bar = getBarConfig(barId);
|
||||
if (!bar || !bar.enabled)
|
||||
return [];
|
||||
|
||||
const conflicts = [];
|
||||
const enabledBars = getEnabledBarConfigs();
|
||||
|
||||
for (var i = 0; i < enabledBars.length; i++) {
|
||||
const other = enabledBars[i];
|
||||
if (other.id === barId)
|
||||
continue;
|
||||
const samePosition = bar.position === other.position;
|
||||
if (!samePosition)
|
||||
continue;
|
||||
const barScreens = bar.screenPreferences || ["all"];
|
||||
const otherScreens = other.screenPreferences || ["all"];
|
||||
|
||||
const hasAll = barScreens.includes("all") || otherScreens.includes("all");
|
||||
if (hasAll) {
|
||||
conflicts.push({
|
||||
"barId": other.id,
|
||||
"barName": other.name,
|
||||
"reason": "Same position on all screens"
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const overlapping = barScreens.some(screen => otherScreens.includes(screen));
|
||||
if (overlapping) {
|
||||
conflicts.push({
|
||||
"barId": other.id,
|
||||
"barName": other.name,
|
||||
"reason": "Same position on overlapping screens"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
function deleteBarConfig(barId) {
|
||||
if (barId === "default")
|
||||
return;
|
||||
@@ -2699,38 +2498,6 @@ Singleton {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
function getFrameFilteredScreens() {
|
||||
var prefs = frameScreenPreferences || ["all"];
|
||||
if (!prefs || prefs.length === 0 || prefs.includes("all")) {
|
||||
return Quickshell.screens;
|
||||
}
|
||||
return Quickshell.screens.filter(screen => isScreenInPreferences(screen, prefs));
|
||||
}
|
||||
|
||||
function getActiveBarEdgeForScreen(screen) {
|
||||
if (!screen)
|
||||
return "";
|
||||
for (var i = 0; i < barConfigs.length; i++) {
|
||||
var bc = barConfigs[i];
|
||||
if (!bc.enabled)
|
||||
continue;
|
||||
var prefs = bc.screenPreferences || ["all"];
|
||||
if (!prefs.includes("all") && !isScreenInPreferences(screen, prefs))
|
||||
continue;
|
||||
switch (bc.position ?? 0) {
|
||||
case SettingsData.Position.Top:
|
||||
return "top";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "bottom";
|
||||
case SettingsData.Position.Left:
|
||||
return "left";
|
||||
case SettingsData.Position.Right:
|
||||
return "right";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function getActiveBarEdgesForScreen(screen) {
|
||||
if (!screen)
|
||||
return [];
|
||||
@@ -2796,46 +2563,6 @@ Singleton {
|
||||
return edges.includes(side) ? frameBarSize : frameThickness;
|
||||
}
|
||||
|
||||
function getActiveBarThicknessForScreen(screen) {
|
||||
if (frameEnabled)
|
||||
return frameBarSize;
|
||||
if (!screen)
|
||||
return frameThickness;
|
||||
for (var i = 0; i < barConfigs.length; i++) {
|
||||
var bc = barConfigs[i];
|
||||
if (!bc.enabled)
|
||||
continue;
|
||||
var prefs = bc.screenPreferences || ["all"];
|
||||
if (!prefs.includes("all") && !isScreenInPreferences(screen, prefs))
|
||||
continue;
|
||||
const innerPadding = bc.innerPadding ?? 4;
|
||||
const barT = Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding));
|
||||
const spacing = bc.spacing ?? 4;
|
||||
const bottomGap = bc.bottomGap ?? 0;
|
||||
return barT + spacing + bottomGap;
|
||||
}
|
||||
return frameThickness;
|
||||
}
|
||||
|
||||
function sendTestNotifications() {
|
||||
NotificationService.dismissAllPopups();
|
||||
sendTestNotification(0);
|
||||
testNotifTimer1.start();
|
||||
testNotifTimer2.start();
|
||||
}
|
||||
|
||||
function sendTestNotification(index) {
|
||||
const notifications = [["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "preferences-system"], ["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "applications-graphics"], ["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "face-smile"]];
|
||||
|
||||
if (index < 0 || index >= notifications.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const notif = notifications[index];
|
||||
testNotificationProcess.command = ["notify-send", "-h", "int:transient:1", "-a", "DMS", "-i", notif[2], notif[0], notif[1]];
|
||||
testNotificationProcess.running = true;
|
||||
}
|
||||
|
||||
function setMatugenScheme(scheme) {
|
||||
var normalized = scheme || "scheme-tonal-spot";
|
||||
if (matugenScheme === normalized)
|
||||
@@ -2852,15 +2579,6 @@ Singleton {
|
||||
set("matugenContrast", value);
|
||||
}
|
||||
|
||||
function setRunUserMatugenTemplates(enabled) {
|
||||
if (runUserMatugenTemplates === enabled)
|
||||
return;
|
||||
set("runUserMatugenTemplates", enabled);
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
}
|
||||
}
|
||||
|
||||
function setMatugenTargetMonitor(monitorName) {
|
||||
if (matugenTargetMonitor === monitorName)
|
||||
return;
|
||||
@@ -2879,11 +2597,6 @@ Singleton {
|
||||
SessionData.setWeatherLocation(displayName, coordinates);
|
||||
}
|
||||
|
||||
function setIconTheme(themeName) {
|
||||
const light = iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode;
|
||||
setIconThemeForMode(themeName, light);
|
||||
}
|
||||
|
||||
function setIconThemeForMode(themeName, light) {
|
||||
if (light)
|
||||
iconThemeLight = themeName;
|
||||
@@ -2929,20 +2642,7 @@ Singleton {
|
||||
// https://github.com/Supreeeme/xwayland-satellite/issues/104
|
||||
// no idea if this matters on other compositors but we also set XCURSOR stuff in the launcher
|
||||
function updateCompositorCursor() {
|
||||
if (typeof CompositorService === "undefined")
|
||||
return;
|
||||
if (CompositorService.isNiri && typeof NiriService !== "undefined") {
|
||||
NiriService.generateNiriCursorConfig();
|
||||
return;
|
||||
}
|
||||
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined") {
|
||||
HyprlandService.generateCursorConfig();
|
||||
return;
|
||||
}
|
||||
if (CompositorService.isMango && typeof MangoService !== "undefined") {
|
||||
MangoService.generateCursorConfig();
|
||||
return;
|
||||
}
|
||||
compositorCursorRefreshNeeded();
|
||||
}
|
||||
|
||||
function updateXResources() {
|
||||
@@ -3010,20 +2710,6 @@ Singleton {
|
||||
return env;
|
||||
}
|
||||
|
||||
function setGtkThemingEnabled(enabled) {
|
||||
set("gtkThemingEnabled", enabled);
|
||||
if (enabled && typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
}
|
||||
}
|
||||
|
||||
function setQtThemingEnabled(enabled) {
|
||||
set("qtThemingEnabled", enabled);
|
||||
if (enabled && typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
}
|
||||
}
|
||||
|
||||
function setShowDock(enabled) {
|
||||
showDock = enabled;
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
@@ -3069,16 +2755,6 @@ Singleton {
|
||||
Qt.callLater(() => forceDockLayoutRefresh());
|
||||
}
|
||||
|
||||
function setDankBarSpacing(spacing) {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (defaultBar) {
|
||||
updateBarConfig(defaultBar.id, {
|
||||
"spacing": spacing
|
||||
});
|
||||
}
|
||||
updateCompositorLayout();
|
||||
}
|
||||
|
||||
function setDankBarPosition(position) {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (!defaultBar)
|
||||
@@ -3134,39 +2810,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function resetDankBarWidgetsToDefault() {
|
||||
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"];
|
||||
var defaultCenter = ["music", "clock", "weather"];
|
||||
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"];
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (defaultBar) {
|
||||
updateBarConfig(defaultBar.id, {
|
||||
"leftWidgets": defaultLeft,
|
||||
"centerWidgets": defaultCenter,
|
||||
"rightWidgets": defaultRight
|
||||
});
|
||||
}
|
||||
updateListModel(leftWidgetsModel, defaultLeft);
|
||||
updateListModel(centerWidgetsModel, defaultCenter);
|
||||
updateListModel(rightWidgetsModel, defaultRight);
|
||||
showLauncherButton = true;
|
||||
showWorkspaceSwitcher = true;
|
||||
showFocusedWindow = true;
|
||||
showWeather = true;
|
||||
showMusic = true;
|
||||
showClipboard = true;
|
||||
showCpuUsage = true;
|
||||
showMemUsage = true;
|
||||
showCpuTemp = true;
|
||||
showGpuTemp = true;
|
||||
showSystemTray = true;
|
||||
showClock = true;
|
||||
showNotificationButton = true;
|
||||
showBattery = true;
|
||||
showControlCenterButton = true;
|
||||
showCapsLockIndicator = true;
|
||||
}
|
||||
|
||||
function setWorkspaceNameIcon(workspaceName, iconData) {
|
||||
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons));
|
||||
iconMap[workspaceName] = iconData;
|
||||
@@ -3448,15 +3091,6 @@ Singleton {
|
||||
Theme.reloadCustomThemeVariant();
|
||||
}
|
||||
|
||||
function toggleDankBarVisible() {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (defaultBar) {
|
||||
updateBarConfig(defaultBar.id, {
|
||||
"visible": !defaultBar.visible
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleShowDock() {
|
||||
setShowDock(!showDock);
|
||||
}
|
||||
@@ -3478,13 +3112,6 @@ Singleton {
|
||||
savePluginSettings();
|
||||
}
|
||||
|
||||
function removePluginSettings(pluginId) {
|
||||
if (pluginSettings[pluginId]) {
|
||||
delete pluginSettings[pluginId];
|
||||
savePluginSettings();
|
||||
}
|
||||
}
|
||||
|
||||
function getPluginSettingsForPlugin(pluginId) {
|
||||
const settings = pluginSettings[pluginId];
|
||||
return settings ? JSON.parse(JSON.stringify(settings)) : {};
|
||||
@@ -3510,22 +3137,6 @@ Singleton {
|
||||
return settings ? JSON.parse(JSON.stringify(settings)) : {};
|
||||
}
|
||||
|
||||
function setNiriOutputSettings(outputId, settings) {
|
||||
const updated = JSON.parse(JSON.stringify(niriOutputSettings));
|
||||
updated[outputId] = settings;
|
||||
niriOutputSettings = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function removeNiriOutputSettings(outputId) {
|
||||
if (!niriOutputSettings[outputId])
|
||||
return;
|
||||
const updated = JSON.parse(JSON.stringify(niriOutputSettings));
|
||||
delete updated[outputId];
|
||||
niriOutputSettings = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getHyprlandOutputSetting(outputId, key, defaultValue) {
|
||||
if (!hyprlandOutputSettings[outputId])
|
||||
return defaultValue;
|
||||
@@ -3550,40 +3161,6 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getHyprlandOutputSettings(outputId) {
|
||||
const settings = hyprlandOutputSettings[outputId];
|
||||
return settings ? JSON.parse(JSON.stringify(settings)) : {};
|
||||
}
|
||||
|
||||
function setHyprlandOutputSettings(outputId, settings) {
|
||||
const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings));
|
||||
updated[outputId] = settings;
|
||||
hyprlandOutputSettings = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function removeHyprlandOutputSettings(outputId) {
|
||||
if (!hyprlandOutputSettings[outputId])
|
||||
return;
|
||||
const updated = JSON.parse(JSON.stringify(hyprlandOutputSettings));
|
||||
delete updated[outputId];
|
||||
hyprlandOutputSettings = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function getDisplayProfiles(compositor) {
|
||||
return displayProfiles[compositor] || {};
|
||||
}
|
||||
|
||||
function setDisplayProfile(compositor, profileId, data) {
|
||||
const updated = JSON.parse(JSON.stringify(displayProfiles));
|
||||
if (!updated[compositor])
|
||||
updated[compositor] = {};
|
||||
updated[compositor][profileId] = data;
|
||||
displayProfiles = updated;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function removeDisplayProfile(compositor, profileId) {
|
||||
if (!displayProfiles[compositor] || !displayProfiles[compositor][profileId])
|
||||
return;
|
||||
@@ -3637,29 +3214,6 @@ Singleton {
|
||||
id: rightWidgetsModel
|
||||
}
|
||||
|
||||
property Process testNotificationProcess
|
||||
|
||||
testNotificationProcess: Process {
|
||||
command: []
|
||||
running: false
|
||||
}
|
||||
|
||||
property Timer testNotifTimer1
|
||||
|
||||
testNotifTimer1: Timer {
|
||||
interval: 400
|
||||
repeat: false
|
||||
onTriggered: sendTestNotification(1)
|
||||
}
|
||||
|
||||
property Timer testNotifTimer2
|
||||
|
||||
testNotifTimer2: Timer {
|
||||
interval: 800
|
||||
repeat: false
|
||||
onTriggered: sendTestNotification(2)
|
||||
}
|
||||
|
||||
property alias settingsFile: settingsFile
|
||||
|
||||
Timer {
|
||||
|
||||
@@ -416,24 +416,6 @@ const StockThemes = {
|
||||
},
|
||||
};
|
||||
|
||||
const ThemeCategories = {
|
||||
GENERIC: {
|
||||
name: "Generic",
|
||||
variants: [
|
||||
"blue",
|
||||
"purple",
|
||||
"green",
|
||||
"orange",
|
||||
"red",
|
||||
"cyan",
|
||||
"pink",
|
||||
"amber",
|
||||
"coral",
|
||||
"monochrome",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const ThemeNames = {
|
||||
BLUE: "blue",
|
||||
PURPLE: "purple",
|
||||
@@ -448,10 +430,6 @@ const ThemeNames = {
|
||||
DYNAMIC: "dynamic",
|
||||
};
|
||||
|
||||
function isStockTheme(themeName) {
|
||||
return Object.keys(StockThemes.DARK).includes(themeName);
|
||||
}
|
||||
|
||||
function getAvailableThemes(isLight = false) {
|
||||
return isLight ? StockThemes.LIGHT : StockThemes.DARK;
|
||||
}
|
||||
@@ -464,7 +442,3 @@ function getThemeByName(themeName, isLight = false) {
|
||||
function getAllThemeNames() {
|
||||
return Object.keys(StockThemes.DARK);
|
||||
}
|
||||
|
||||
function getThemeCategories() {
|
||||
return ThemeCategories;
|
||||
}
|
||||
|
||||
+17
-602
@@ -107,8 +107,11 @@ Singleton {
|
||||
property int _colorsRetryCount: 0
|
||||
property double _lastGenerateMs: 0
|
||||
|
||||
property bool themeModeAutomationActive: false
|
||||
property bool dmsServiceWasDisconnected: true
|
||||
property bool blurLayersActive: false
|
||||
property bool matugenToastSuppressed: false
|
||||
|
||||
signal screenTransitionNeeded
|
||||
signal themeGenerationStarting
|
||||
|
||||
readonly property var dank16: {
|
||||
const raw = matugenColors?.dank16;
|
||||
@@ -196,235 +199,6 @@ Singleton {
|
||||
const currentIsLight = (typeof SessionData !== "undefined") ? SessionData.isLightMode : false;
|
||||
SettingsData.updateCosmicThemeMode(currentIsLight);
|
||||
}
|
||||
|
||||
if (typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled) {
|
||||
startThemeModeAutomation();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
enabled: typeof SessionData !== "undefined"
|
||||
|
||||
function onThemeModeAutoEnabledChanged() {
|
||||
if (SessionData.themeModeAutoEnabled) {
|
||||
root.startThemeModeAutomation();
|
||||
} else {
|
||||
root.stopThemeModeAutomation();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeAutoModeChanged() {
|
||||
if (root.themeModeAutomationActive) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeStartHourChanged() {
|
||||
if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeStartMinuteChanged() {
|
||||
if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeEndHourChanged() {
|
||||
if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeEndMinuteChanged() {
|
||||
if (root.themeModeAutomationActive && !SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onThemeModeShareGammaSettingsChanged() {
|
||||
if (root.themeModeAutomationActive) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onNightModeStartHourChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onNightModeStartMinuteChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onNightModeEndHourChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onNightModeEndMinuteChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeShareGammaSettings) {
|
||||
root.evaluateThemeMode();
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onLatitudeChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") {
|
||||
if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0 && typeof DMSService !== "undefined") {
|
||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
});
|
||||
}
|
||||
root.evaluateThemeMode();
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onLongitudeChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") {
|
||||
if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0 && typeof DMSService !== "undefined") {
|
||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
});
|
||||
}
|
||||
root.evaluateThemeMode();
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
function onNightModeUseIPLocationChanged() {
|
||||
if (root.themeModeAutomationActive && SessionData.themeModeAutoMode === "location") {
|
||||
if (typeof DMSService !== "undefined") {
|
||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||
"use": SessionData.nightModeUseIPLocation
|
||||
}, response => {
|
||||
if (!response.error && !SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
root.evaluateThemeMode();
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// React to gamma backend's isDay state changes for location-based mode
|
||||
Connections {
|
||||
target: DisplayService
|
||||
enabled: typeof DisplayService !== "undefined" && typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "location" && !themeAutoBackendAvailable()
|
||||
|
||||
function onGammaIsDayChanged() {
|
||||
if (root.isLightMode !== DisplayService.gammaIsDay) {
|
||||
root.setLightMode(DisplayService.gammaIsDay, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function onThemeAutoStateUpdate(data) {
|
||||
if (!SessionData.themeModeAutoEnabled) {
|
||||
return;
|
||||
}
|
||||
applyThemeAutoState(data);
|
||||
}
|
||||
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected && SessionData.themeModeAutoMode === "time") {
|
||||
root.syncTimeThemeSchedule();
|
||||
}
|
||||
|
||||
if (DMSService.isConnected && SessionData.themeModeAutoMode === "location") {
|
||||
root.syncLocationThemeSchedule();
|
||||
}
|
||||
|
||||
if (themeAutoBackendAvailable() && SessionData.themeModeAutoEnabled) {
|
||||
DMSService.sendRequest("theme.auto.getState", null, response => {
|
||||
if (response && response.result) {
|
||||
applyThemeAutoState(response.result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!SessionData.themeModeAutoEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DMSService.isConnected && SessionData.themeModeAutoMode === "location") {
|
||||
if (SessionData.nightModeUseIPLocation) {
|
||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||
"use": true
|
||||
}, response => {
|
||||
if (!response.error) {
|
||||
log.info("Theme automation: IP location enabled after connection");
|
||||
}
|
||||
});
|
||||
} else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||
"use": false
|
||||
}, response => {
|
||||
if (!response.error) {
|
||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
}, locationResponse => {
|
||||
if (locationResponse?.error) {
|
||||
log.warn("Theme automation: Failed to set location", locationResponse.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.warn("Theme automation: No location configured");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
enabled: SessionData.themeModeAutoEnabled
|
||||
|
||||
function onSessionUnlocked() {
|
||||
root.triggerThemeAutomationRefresh();
|
||||
}
|
||||
|
||||
function onSessionResumed() {
|
||||
root.triggerThemeAutomationRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
function triggerThemeAutomationRefresh() {
|
||||
if (!themeAutoBackendAvailable()) {
|
||||
root.evaluateThemeMode();
|
||||
return;
|
||||
}
|
||||
DMSService.sendRequest("theme.auto.trigger", {});
|
||||
}
|
||||
|
||||
function getMatugenColor(path, fallback) {
|
||||
@@ -571,8 +345,8 @@ Singleton {
|
||||
property color surfaceVariantAlpha: withAlpha(surfaceVariant, 0.2)
|
||||
|
||||
readonly property bool foregroundLayers: typeof SettingsData === "undefined" || (SettingsData.blurForegroundLayers ?? true)
|
||||
readonly property bool blurForegroundLayers: BlurService.enabled && foregroundLayers
|
||||
readonly property bool transparentBlurLayers: BlurService.enabled && !foregroundLayers
|
||||
readonly property bool blurForegroundLayers: blurLayersActive && foregroundLayers
|
||||
readonly property bool transparentBlurLayers: blurLayersActive && !foregroundLayers
|
||||
readonly property bool notificationForegroundLayers: typeof SettingsData === "undefined" || (SettingsData.notificationForegroundLayers ?? true)
|
||||
readonly property color readableSurface: withAlpha(surfaceContainer, popupTransparency)
|
||||
readonly property color readableSurfaceHigh: withAlpha(surfaceContainerHigh, popupTransparency)
|
||||
@@ -658,7 +432,7 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
readonly property color ccTileInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.16) : (foregroundLayers ? withAlpha(surfaceContainerHigh, BlurService.enabled ? Math.min(popupTransparency, 0.24) : popupTransparency) : withAlpha(surfaceContainer, 0))
|
||||
readonly property color ccTileInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.16) : (foregroundLayers ? withAlpha(surfaceContainerHigh, blurLayersActive ? Math.min(popupTransparency, 0.24) : popupTransparency) : withAlpha(surfaceContainer, 0))
|
||||
readonly property color ccPillInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.08) : nestedSurface
|
||||
readonly property color ccPillInactiveHoverBg: transparentBlurLayers ? withAlpha(primary, 0.10) : primaryPressed
|
||||
readonly property color ccSliderTrackColor: transparentBlurLayers ? surfaceText : surfaceContainerHigh
|
||||
@@ -978,22 +752,6 @@ Singleton {
|
||||
};
|
||||
}
|
||||
|
||||
function elevationTintOpacity(level) {
|
||||
if (!level)
|
||||
return 0;
|
||||
if (level === elevationLevel1)
|
||||
return 0.05;
|
||||
if (level === elevationLevel2)
|
||||
return 0.08;
|
||||
if (level === elevationLevel3)
|
||||
return 0.11;
|
||||
if (level === elevationLevel4)
|
||||
return 0.12;
|
||||
if (level === elevationLevel5)
|
||||
return 0.14;
|
||||
return 0.08;
|
||||
}
|
||||
|
||||
readonly property var animationDurations: [
|
||||
{
|
||||
"shorter": 0,
|
||||
@@ -1261,9 +1019,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function screenTransition() {
|
||||
if (CompositorService.isNiri) {
|
||||
NiriService.doScreenTransition();
|
||||
}
|
||||
screenTransitionNeeded();
|
||||
}
|
||||
|
||||
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
|
||||
@@ -1315,7 +1071,6 @@ Singleton {
|
||||
SessionData.setLightMode(light);
|
||||
}
|
||||
|
||||
PortalService.setLightMode(light);
|
||||
if (typeof SettingsData !== "undefined") {
|
||||
SettingsData.updateCosmicThemeMode(light);
|
||||
}
|
||||
@@ -1326,22 +1081,6 @@ Singleton {
|
||||
setLightMode(!isLightMode, savePrefs, true);
|
||||
}
|
||||
|
||||
function forceGenerateSystemThemes() {
|
||||
if (!matugenAvailable) {
|
||||
return;
|
||||
}
|
||||
generateSystemThemesFromCurrentTheme();
|
||||
}
|
||||
|
||||
function getAvailableThemes() {
|
||||
return StockThemes.getAllThemeNames();
|
||||
}
|
||||
|
||||
function getThemeDisplayName(themeName) {
|
||||
const themeData = StockThemes.getThemeByName(themeName, isLightMode);
|
||||
return themeData.name;
|
||||
}
|
||||
|
||||
function getThemeColors(themeName) {
|
||||
if (themeName === "custom" && customThemeData) {
|
||||
return customThemeData;
|
||||
@@ -1457,10 +1196,6 @@ Singleton {
|
||||
readonly property var _availableThemeNames: StockThemes.getAllThemeNames()
|
||||
property string currentThemeName: currentTheme
|
||||
|
||||
function panelBackground() {
|
||||
return withAlpha(surfaceContainer, panelTransparency);
|
||||
}
|
||||
|
||||
property real notepadTransparency: SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : popupTransparency
|
||||
|
||||
property bool widgetBackgroundHasAlpha: {
|
||||
@@ -1537,10 +1272,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function isColorDark(c) {
|
||||
return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b) < 0.5;
|
||||
}
|
||||
|
||||
function barIconSize(barThickness, offset, maximizeIcon, iconScale) {
|
||||
const defaultOffset = offset !== undefined ? offset : -6;
|
||||
const size = (maximizeIcon ?? false) ? iconSizeLarge : iconSize;
|
||||
@@ -1623,19 +1354,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function getPowerProfileDescription(profile) {
|
||||
switch (profile) {
|
||||
case 0:
|
||||
return I18n.tr("Extend battery life", "power profile description");
|
||||
case 1:
|
||||
return I18n.tr("Balance power and performance", "power profile description");
|
||||
case 2:
|
||||
return I18n.tr("Prioritize performance", "power profile description");
|
||||
default:
|
||||
return I18n.tr("Custom power profile", "power profile description");
|
||||
}
|
||||
}
|
||||
|
||||
function onLightModeChanged() {
|
||||
if (currentTheme === "custom" && customThemeFileView.path) {
|
||||
customThemeFileView.reload();
|
||||
@@ -1663,9 +1381,7 @@ Singleton {
|
||||
|
||||
log.info("Setting desired theme -", kind, "mode:", isLight ? "light" : "dark", stockColors ? "(stock colors)" : "(dynamic)");
|
||||
|
||||
if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
|
||||
NiriService.suppressNextToast();
|
||||
}
|
||||
themeGenerationStarting();
|
||||
|
||||
const desired = {
|
||||
"kind": kind,
|
||||
@@ -1777,8 +1493,7 @@ Singleton {
|
||||
|
||||
if (currentTheme === dynamic) {
|
||||
if (!rawWallpaperPath) {
|
||||
log.warn("Auto theme has no wallpaper - skipping matugen, syncing portal mode only");
|
||||
PortalService.setLightMode(isLight);
|
||||
log.warn("Auto theme has no wallpaper - skipping matugen");
|
||||
return;
|
||||
}
|
||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
|
||||
@@ -1978,7 +1693,7 @@ Singleton {
|
||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "true" : "false";
|
||||
Proc.runCommand("gtkApplier", ["bash", shellDir + "/scripts/gtk.sh", configDir, "apply", isLight, shellDir], (output, exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
if (typeof ToastService !== "undefined" && typeof NiriService !== "undefined" && !NiriService.matugenSuppression) {
|
||||
if (typeof ToastService !== "undefined" && !root.matugenToastSuppressed) {
|
||||
ToastService.showInfo(I18n.tr("GTK colors applied successfully"));
|
||||
}
|
||||
} else {
|
||||
@@ -2016,18 +1731,17 @@ Singleton {
|
||||
return Qt.rgba(c.r, c.g, c.b, a);
|
||||
}
|
||||
|
||||
function popupLayerColor(baseColor) {
|
||||
if (isConnectedEffect)
|
||||
return connectedSurfaceColor;
|
||||
return withAlpha(baseColor, popupTransparency);
|
||||
}
|
||||
|
||||
function blendAlpha(c, a) {
|
||||
if (!c || c.r === undefined)
|
||||
return Qt.rgba(0, 0, 0, 0);
|
||||
return Qt.rgba(c.r, c.g, c.b, c.a * a);
|
||||
}
|
||||
|
||||
function hoverTint(base) {
|
||||
const factor = 1.2;
|
||||
return isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
|
||||
}
|
||||
|
||||
function blend(c1, c2, r) {
|
||||
return Qt.rgba(c1.r * (1 - r) + c2.r * r, c1.g * (1 - r) + c2.g * r, c1.b * (1 - r) + c2.b * r, c1.a * (1 - r) + c2.a * r);
|
||||
}
|
||||
@@ -2344,303 +2058,4 @@ Singleton {
|
||||
root.switchTheme(defaultTheme, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Theme mode automation functions
|
||||
function themeAutoBackendAvailable() {
|
||||
return typeof DMSService !== "undefined" && DMSService.isConnected && Array.isArray(DMSService.capabilities) && DMSService.capabilities.includes("theme.auto");
|
||||
}
|
||||
|
||||
function applyThemeAutoState(state) {
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
if (state.config && state.config.mode && state.config.mode !== SessionData.themeModeAutoMode) {
|
||||
return;
|
||||
}
|
||||
if (typeof SessionData !== "undefined" && state.nextTransition !== undefined) {
|
||||
SessionData.themeModeNextTransition = state.nextTransition || "";
|
||||
}
|
||||
if (state.isLight !== undefined && root.isLightMode !== state.isLight) {
|
||||
root.setLightMode(state.isLight, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
function syncTimeThemeSchedule() {
|
||||
if (typeof SessionData === "undefined" || typeof DMSService === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DMSService.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeModeActive = SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "time";
|
||||
|
||||
if (!timeModeActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
DMSService.sendRequest("theme.auto.setMode", {
|
||||
"mode": "time"
|
||||
});
|
||||
|
||||
const shareSettings = SessionData.themeModeShareGammaSettings;
|
||||
const startHour = shareSettings ? SessionData.nightModeStartHour : SessionData.themeModeStartHour;
|
||||
const startMinute = shareSettings ? SessionData.nightModeStartMinute : SessionData.themeModeStartMinute;
|
||||
const endHour = shareSettings ? SessionData.nightModeEndHour : SessionData.themeModeEndHour;
|
||||
const endMinute = shareSettings ? SessionData.nightModeEndMinute : SessionData.themeModeEndMinute;
|
||||
|
||||
DMSService.sendRequest("theme.auto.setSchedule", {
|
||||
"startHour": startHour,
|
||||
"startMinute": startMinute,
|
||||
"endHour": endHour,
|
||||
"endMinute": endMinute
|
||||
}, response => {
|
||||
if (response && response.error) {
|
||||
log.error("Theme automation: Failed to sync time schedule:", response.error);
|
||||
}
|
||||
});
|
||||
|
||||
DMSService.sendRequest("theme.auto.setEnabled", {
|
||||
"enabled": true
|
||||
});
|
||||
DMSService.sendRequest("theme.auto.trigger", {});
|
||||
}
|
||||
|
||||
function syncLocationThemeSchedule() {
|
||||
if (typeof SessionData === "undefined" || typeof DMSService === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DMSService.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const locationModeActive = SessionData.themeModeAutoEnabled && SessionData.themeModeAutoMode === "location";
|
||||
|
||||
if (!locationModeActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
DMSService.sendRequest("theme.auto.setMode", {
|
||||
"mode": "location"
|
||||
});
|
||||
|
||||
if (SessionData.nightModeUseIPLocation) {
|
||||
DMSService.sendRequest("theme.auto.setUseIPLocation", {
|
||||
"use": true
|
||||
});
|
||||
} else {
|
||||
DMSService.sendRequest("theme.auto.setUseIPLocation", {
|
||||
"use": false
|
||||
});
|
||||
if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
DMSService.sendRequest("theme.auto.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DMSService.sendRequest("theme.auto.setEnabled", {
|
||||
"enabled": true
|
||||
});
|
||||
DMSService.sendRequest("theme.auto.trigger", {});
|
||||
}
|
||||
|
||||
function evaluateThemeMode() {
|
||||
if (typeof SessionData === "undefined" || !SessionData.themeModeAutoEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (themeAutoBackendAvailable()) {
|
||||
DMSService.sendRequest("theme.auto.getState", null, response => {
|
||||
if (response && response.result) {
|
||||
applyThemeAutoState(response.result);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const mode = SessionData.themeModeAutoMode;
|
||||
|
||||
if (mode === "location") {
|
||||
evaluateLocationBasedThemeMode();
|
||||
} else {
|
||||
evaluateTimeBasedThemeMode();
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateLocationBasedThemeMode() {
|
||||
if (typeof DisplayService !== "undefined") {
|
||||
const shouldBeLight = DisplayService.gammaIsDay;
|
||||
if (root.isLightMode !== shouldBeLight) {
|
||||
root.setLightMode(shouldBeLight, true, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SessionData.nightModeUseIPLocation && SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
const shouldBeLight = calculateIsDaytime(SessionData.latitude, SessionData.longitude);
|
||||
if (root.isLightMode !== shouldBeLight) {
|
||||
root.setLightMode(shouldBeLight, true, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.themeModeAutomationActive) {
|
||||
if (SessionData.nightModeUseIPLocation) {
|
||||
log.warn("Theme automation: Waiting for IP location from backend");
|
||||
} else {
|
||||
log.warn("Theme automation: Location mode requires coordinates");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateTimeBasedThemeMode() {
|
||||
const shareSettings = SessionData.themeModeShareGammaSettings;
|
||||
|
||||
const startHour = shareSettings ? SessionData.nightModeStartHour : SessionData.themeModeStartHour;
|
||||
const startMinute = shareSettings ? SessionData.nightModeStartMinute : SessionData.themeModeStartMinute;
|
||||
const endHour = shareSettings ? SessionData.nightModeEndHour : SessionData.themeModeEndHour;
|
||||
const endMinute = shareSettings ? SessionData.nightModeEndMinute : SessionData.themeModeEndMinute;
|
||||
|
||||
const now = new Date();
|
||||
const currentMinutes = now.getHours() * 60 + now.getMinutes();
|
||||
const startMinutes = startHour * 60 + startMinute;
|
||||
const endMinutes = endHour * 60 + endMinute;
|
||||
|
||||
let shouldBeLight;
|
||||
if (startMinutes < endMinutes) {
|
||||
shouldBeLight = currentMinutes < startMinutes || currentMinutes >= endMinutes;
|
||||
} else {
|
||||
shouldBeLight = currentMinutes >= endMinutes && currentMinutes < startMinutes;
|
||||
}
|
||||
|
||||
if (root.isLightMode !== shouldBeLight) {
|
||||
root.setLightMode(shouldBeLight, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateIsDaytime(lat, lng) {
|
||||
const now = new Date();
|
||||
const start = new Date(now.getFullYear(), 0, 0);
|
||||
const diff = now - start;
|
||||
const dayOfYear = Math.floor(diff / 86400000);
|
||||
const latRad = lat * Math.PI / 180;
|
||||
|
||||
const declination = 23.45 * Math.sin((360 / 365) * (dayOfYear - 81) * Math.PI / 180);
|
||||
const declinationRad = declination * Math.PI / 180;
|
||||
|
||||
const cosHourAngle = -Math.tan(latRad) * Math.tan(declinationRad);
|
||||
|
||||
if (cosHourAngle > 1) {
|
||||
return false; // Polar night
|
||||
}
|
||||
if (cosHourAngle < -1) {
|
||||
return true; // Midnight sun
|
||||
}
|
||||
|
||||
const hourAngle = Math.acos(cosHourAngle);
|
||||
const hourAngleDeg = hourAngle * 180 / Math.PI;
|
||||
|
||||
const sunriseHour = 12 - hourAngleDeg / 15;
|
||||
const sunsetHour = 12 + hourAngleDeg / 15;
|
||||
|
||||
const timeZoneOffset = now.getTimezoneOffset() / 60;
|
||||
const localSunrise = sunriseHour - lng / 15 - timeZoneOffset;
|
||||
const localSunset = sunsetHour - lng / 15 - timeZoneOffset;
|
||||
|
||||
const currentHour = now.getHours() + now.getMinutes() / 60;
|
||||
|
||||
const normalizeSunrise = ((localSunrise % 24) + 24) % 24;
|
||||
const normalizeSunset = ((localSunset % 24) + 24) % 24;
|
||||
|
||||
return currentHour >= normalizeSunrise && currentHour < normalizeSunset;
|
||||
}
|
||||
|
||||
// Helper function to send location to backend
|
||||
function sendLocationToBackend() {
|
||||
if (typeof SessionData === "undefined" || typeof DMSService === "undefined") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DMSService.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SessionData.nightModeUseIPLocation) {
|
||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||
"use": true
|
||||
}, response => {
|
||||
if (response?.error) {
|
||||
log.warn("Theme automation: Failed to enable IP location", response.error);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||
"use": false
|
||||
}, response => {
|
||||
if (!response.error) {
|
||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||
"latitude": SessionData.latitude,
|
||||
"longitude": SessionData.longitude
|
||||
}, locResp => {
|
||||
if (locResp?.error) {
|
||||
log.warn("Theme automation: Failed to set location", locResp.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: locationRetryTimer
|
||||
interval: 1000
|
||||
repeat: true
|
||||
running: false
|
||||
property int retryCount: 0
|
||||
|
||||
onTriggered: {
|
||||
if (root.sendLocationToBackend()) {
|
||||
stop();
|
||||
retryCount = 0;
|
||||
root.evaluateThemeMode();
|
||||
} else {
|
||||
retryCount++;
|
||||
if (retryCount >= 10) {
|
||||
stop();
|
||||
retryCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startThemeModeAutomation() {
|
||||
root.themeModeAutomationActive = true;
|
||||
|
||||
root.syncTimeThemeSchedule();
|
||||
root.syncLocationThemeSchedule();
|
||||
|
||||
const sent = root.sendLocationToBackend();
|
||||
|
||||
if (!sent && typeof SessionData !== "undefined" && SessionData.themeModeAutoMode === "location") {
|
||||
locationRetryTimer.start();
|
||||
} else {
|
||||
root.evaluateThemeMode();
|
||||
}
|
||||
}
|
||||
|
||||
function stopThemeModeAutomation() {
|
||||
root.themeModeAutomationActive = false;
|
||||
if (typeof DMSService !== "undefined" && DMSService.isConnected) {
|
||||
DMSService.sendRequest("theme.auto.setEnabled", {
|
||||
"enabled": false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,13 @@
|
||||
function markdownToHtml(text) {
|
||||
if (!text) return "";
|
||||
|
||||
// Store code blocks and inline code to protect them from further processing
|
||||
const codeBlocks = [];
|
||||
const inlineCode = [];
|
||||
let blockIndex = 0;
|
||||
let inlineIndex = 0;
|
||||
|
||||
// First, extract and replace code blocks with placeholders
|
||||
let html = text.replace(/```([\s\S]*?)```/g, (match, code) => {
|
||||
// Trim leading and trailing blank lines only
|
||||
const trimmedCode = code.replace(/^\n+|\n+$/g, '');
|
||||
// Escape HTML entities in code
|
||||
const escapedCode = trimmedCode.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
@@ -22,9 +18,7 @@ function markdownToHtml(text) {
|
||||
return `\x00CODEBLOCK${blockIndex++}\x00`;
|
||||
});
|
||||
|
||||
// Extract and replace inline code
|
||||
html = html.replace(/`([^`]+)`/g, (match, code) => {
|
||||
// Escape HTML entities in code
|
||||
const escapedCode = code.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
@@ -40,12 +34,10 @@ function markdownToHtml(text) {
|
||||
return prefix + `\x00URL${urlIndex++}\x00`;
|
||||
});
|
||||
|
||||
// Escape HTML entities (but not in code blocks or URLs)
|
||||
html = html.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
|
||||
// Headers
|
||||
html = html.replace(/^### (.*?)$/gm, '<h3>$1</h3>');
|
||||
html = html.replace(/^## (.*?)$/gm, '<h2>$1</h2>');
|
||||
html = html.replace(/^# (.*?)$/gm, '<h1>$1</h1>');
|
||||
@@ -58,20 +50,16 @@ function markdownToHtml(text) {
|
||||
html = html.replace(/__(.*?)__/g, '<b>$1</b>');
|
||||
html = html.replace(/_(.*?)_/g, '<i>$1</i>');
|
||||
|
||||
// Links
|
||||
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
||||
|
||||
// Lists
|
||||
html = html.replace(/^\* (.*?)$/gm, '<li>$1</li>');
|
||||
html = html.replace(/^- (.*?)$/gm, '<li>$1</li>');
|
||||
html = html.replace(/^\d+\. (.*?)$/gm, '<li>$1</li>');
|
||||
|
||||
// Wrap consecutive list items in ul/ol tags
|
||||
html = html.replace(/(<li>[\s\S]*?<\/li>\s*)+/g, function(match) {
|
||||
return '<ul>' + match + '</ul>';
|
||||
});
|
||||
|
||||
// Restore extracted URLs as anchor tags (preserves raw & in href)
|
||||
html = html.replace(/\x00URL(\d+)\x00/g, (_, index) => {
|
||||
const url = urls[parseInt(index)];
|
||||
const display = url.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
@@ -87,30 +75,23 @@ function markdownToHtml(text) {
|
||||
return inlineCode[parseInt(index)];
|
||||
});
|
||||
|
||||
// Line breaks (after code blocks are restored)
|
||||
html = html.replace(/\n\n/g, '</p><p>');
|
||||
html = html.replace(/\n/g, '<br/>');
|
||||
|
||||
// Wrap in paragraph tags if not already wrapped
|
||||
if (!html.startsWith('<')) {
|
||||
html = '<p>' + html + '</p>';
|
||||
}
|
||||
|
||||
// Clean up the final HTML
|
||||
// Remove <br/> tags immediately before block elements
|
||||
html = html.replace(/<br\/>\s*<pre>/g, '<pre>');
|
||||
html = html.replace(/<br\/>\s*<ul>/g, '<ul>');
|
||||
html = html.replace(/<br\/>\s*<h[1-6]>/g, '<h$1>');
|
||||
|
||||
// Remove empty paragraphs
|
||||
html = html.replace(/<p>\s*<\/p>/g, '');
|
||||
html = html.replace(/<p>\s*<br\/>\s*<\/p>/g, '');
|
||||
|
||||
// Remove excessive line breaks
|
||||
html = html.replace(/(<br\/>){3,}/g, '<br/><br/>'); // Max 2 consecutive line breaks
|
||||
html = html.replace(/(<\/p>)\s*(<p>)/g, '$1$2'); // Remove whitespace between paragraphs
|
||||
html = html.replace(/(<br\/>){3,}/g, '<br/><br/>');
|
||||
html = html.replace(/(<\/p>)\s*(<p>)/g, '$1$2');
|
||||
|
||||
// Remove leading/trailing whitespace
|
||||
html = html.trim();
|
||||
|
||||
return html;
|
||||
|
||||
@@ -5,11 +5,13 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
signal toastRequested(int severity, string title, string body, string command, string category)
|
||||
signal toastCategoryDismissed(string category)
|
||||
|
||||
property var settingsRoot: null
|
||||
|
||||
onSettingsRootChanged: {
|
||||
@@ -317,7 +319,7 @@ Singleton {
|
||||
function launchAuthApplyTerminalFallback(fromPrecheck, details) {
|
||||
authApplyTerminalFallbackFromPrecheck = fromPrecheck;
|
||||
if (details && details !== "")
|
||||
ToastService.showInfo(I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync");
|
||||
toastRequested(0, I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync");
|
||||
authApplyTerminalFallbackStderr = "";
|
||||
authApplyTerminalFallbackProcess.running = true;
|
||||
}
|
||||
@@ -364,21 +366,21 @@ Singleton {
|
||||
}
|
||||
|
||||
function deferGreeterAutoLoginSyncToPill(details) {
|
||||
ToastService.dismissCategory("greeter-autologin-sync");
|
||||
toastCategoryDismissed("greeter-autologin-sync");
|
||||
if (settingsRoot)
|
||||
settingsRoot.set("greeterSyncPending", true);
|
||||
ToastService.showWarning(I18n.tr("Auto-login change needs a sync"), I18n.tr("Administrator access is required. Use the Sync button in Settings → Greeter to apply.") + (details ? "\n\n" + details : ""), "dms-greeter sync --autologin", "greeter-autologin-sync");
|
||||
toastRequested(1, I18n.tr("Auto-login change needs a sync"), I18n.tr("Administrator access is required. Use the Sync button in Settings → Greeter to apply.") + (details ? "\n\n" + details : ""), "dms-greeter sync --autologin", "greeter-autologin-sync");
|
||||
finishGreeterAutoLoginSync();
|
||||
}
|
||||
|
||||
function greeterAutoLoginSyncSuccessToast(details) {
|
||||
const enabling = settingsRoot && settingsRoot.greeterAutoLogin;
|
||||
// Clear the sticky in-progress toast, then confirm with an auto-dismissing toast.
|
||||
ToastService.dismissCategory("greeter-autologin-sync");
|
||||
toastCategoryDismissed("greeter-autologin-sync");
|
||||
if (enabling) {
|
||||
ToastService.showWarning(I18n.tr("Auto-login enabled"), I18n.tr("You'll skip the greeter password after the next reboot. The lock screen and signing out still require your password.") + (details ? "\n\n" + details : ""));
|
||||
toastRequested(1, I18n.tr("Auto-login enabled"), I18n.tr("You'll skip the greeter password after the next reboot. The lock screen and signing out still require your password.") + (details ? "\n\n" + details : ""), "", "");
|
||||
} else {
|
||||
ToastService.showInfo(I18n.tr("Auto-login disabled"), I18n.tr("You'll enter your password at the greeter after the next reboot.") + (details ? "\n\n" + details : ""));
|
||||
toastRequested(0, I18n.tr("Auto-login disabled"), I18n.tr("You'll enter your password at the greeter after the next reboot.") + (details ? "\n\n" + details : ""), "", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +577,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
const enabling = root.settingsRoot && root.settingsRoot.greeterAutoLogin;
|
||||
if (exitCode === 0) {
|
||||
ToastService.showWarning(enabling ? I18n.tr("Applying auto-login on startup...") : I18n.tr("Disabling auto-login on startup..."), "", "dms-greeter sync --autologin", "greeter-autologin-sync");
|
||||
root.toastRequested(1, enabling ? I18n.tr("Applying auto-login on startup...") : I18n.tr("Disabling auto-login on startup..."), "", "dms-greeter sync --autologin", "greeter-autologin-sync");
|
||||
root.greeterAutoLoginSyncProcess.running = true;
|
||||
return;
|
||||
}
|
||||
@@ -604,7 +606,7 @@ Singleton {
|
||||
let details = out;
|
||||
if (err !== "")
|
||||
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
|
||||
ToastService.showInfo(I18n.tr("Authentication changes applied"), details, "", "auth-sync");
|
||||
root.toastRequested(0, I18n.tr("Authentication changes applied"), details, "", "auth-sync");
|
||||
root.detectAuthCapabilities();
|
||||
root.finishAuthApply();
|
||||
return;
|
||||
@@ -615,7 +617,7 @@ Singleton {
|
||||
details = out;
|
||||
if (err !== "")
|
||||
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
|
||||
ToastService.showWarning(I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync");
|
||||
root.toastRequested(1, I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync");
|
||||
root.launchAuthApplyTerminalFallback(false, "");
|
||||
}
|
||||
}
|
||||
@@ -631,7 +633,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
const err = (root.authApplySudoProbeStderr || "").trim();
|
||||
if (exitCode === 0) {
|
||||
ToastService.showInfo(I18n.tr("Applying authentication changes..."), "", "", "auth-sync");
|
||||
root.toastRequested(0, I18n.tr("Applying authentication changes..."), "", "", "auth-sync");
|
||||
root.authApplyProcess.running = true;
|
||||
return;
|
||||
}
|
||||
@@ -651,10 +653,10 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
const message = root.authApplyTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication there; it will close automatically when done.");
|
||||
ToastService.showInfo(message, "", "", "auth-sync");
|
||||
root.toastRequested(0, message, "", "", "auth-sync");
|
||||
} else {
|
||||
let details = (root.authApplyTerminalFallbackStderr || "").trim();
|
||||
ToastService.showError(I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync");
|
||||
root.toastRequested(2, I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync");
|
||||
}
|
||||
root.finishAuthApply();
|
||||
}
|
||||
|
||||
@@ -75,26 +75,3 @@ function migrateToVersion(obj, targetVersion, settingsData) {
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
function cleanup(fileText) {
|
||||
var getValidKeys = SpecModule.getValidKeys;
|
||||
if (!fileText || !fileText.trim()) return null;
|
||||
|
||||
try {
|
||||
var session = JSON.parse(fileText);
|
||||
var validKeys = getValidKeys();
|
||||
var needsSave = false;
|
||||
|
||||
for (var key in session) {
|
||||
if (validKeys.indexOf(key) < 0) {
|
||||
delete session[key];
|
||||
needsSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
return needsSave ? JSON.stringify(session, null, 2) : null;
|
||||
} catch (e) {
|
||||
console.warn("SessionData: Failed to cleanup unused keys:", e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,26 +291,3 @@ function migrateToVersion(obj, targetVersion) {
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
function cleanup(fileText) {
|
||||
var getValidKeys = SpecModule.getValidKeys;
|
||||
if (!fileText || !fileText.trim()) return;
|
||||
|
||||
try {
|
||||
var settings = JSON.parse(fileText);
|
||||
var validKeys = getValidKeys();
|
||||
var needsSave = false;
|
||||
|
||||
for (var key in settings) {
|
||||
if (validKeys.indexOf(key) < 0) {
|
||||
delete settings[key];
|
||||
needsSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
return needsSave ? JSON.stringify(settings, null, 2) : null;
|
||||
} catch (e) {
|
||||
console.warn("SettingsData: Failed to cleanup unused keys:", e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,11 +122,6 @@ const times = [
|
||||
|
||||
// adds a custom time to the times config
|
||||
|
||||
function addTime(angle, riseName, setName) {
|
||||
times.push([angle, riseName, setName]);
|
||||
};
|
||||
|
||||
|
||||
// calculations for sun times
|
||||
|
||||
const J0 = 0.0009;
|
||||
@@ -246,63 +241,3 @@ function getMoonIllumination(date) {
|
||||
angle
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function hoursLater(date, h) {
|
||||
return new Date(date.valueOf() + h * dayMs / 24);
|
||||
}
|
||||
|
||||
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
|
||||
|
||||
function getMoonTimes(date, lat, lng, inUTC) {
|
||||
const t = new Date(date);
|
||||
if (inUTC) t.setUTCHours(0, 0, 0, 0);
|
||||
else t.setHours(0, 0, 0, 0);
|
||||
|
||||
const hc = 0.133 * rad;
|
||||
let h0 = getMoonPosition(t, lat, lng).altitude - hc,
|
||||
rise, set, ye;
|
||||
|
||||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
|
||||
for (let i = 1; i <= 24; i += 2) {
|
||||
const h1 = getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
|
||||
const h2 = getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
|
||||
const a = (h0 + h2) / 2 - h1;
|
||||
const b = (h2 - h0) / 2;
|
||||
const xe = -b / (2 * a);
|
||||
const d = b * b - 4 * a * h1;
|
||||
let roots = 0, x1 = 0, x2 = 0;
|
||||
ye = (a * xe + b) * xe + h1;
|
||||
|
||||
if (d >= 0) {
|
||||
const dx = Math.sqrt(d) / (Math.abs(a) * 2);
|
||||
x1 = xe - dx;
|
||||
x2 = xe + dx;
|
||||
if (Math.abs(x1) <= 1) roots++;
|
||||
if (Math.abs(x2) <= 1) roots++;
|
||||
if (x1 < -1) x1 = x2;
|
||||
}
|
||||
|
||||
if (roots === 1) {
|
||||
if (h0 < 0) rise = i + x1;
|
||||
else set = i + x1;
|
||||
|
||||
} else if (roots === 2) {
|
||||
rise = i + (ye < 0 ? x2 : x1);
|
||||
set = i + (ye < 0 ? x1 : x2);
|
||||
}
|
||||
|
||||
if (rise && set) break;
|
||||
|
||||
h0 = h2;
|
||||
}
|
||||
|
||||
const result = {};
|
||||
|
||||
if (rise) result.rise = hoursLater(t, rise);
|
||||
if (set) result.set = hoursLater(t, set);
|
||||
|
||||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user