mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
switch hto monorepo structure
This commit is contained in:
25
quickshell/Common/Anims.qml
Normal file
25
quickshell/Common/Anims.qml
Normal file
@@ -0,0 +1,25 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int durShort: 200
|
||||
readonly property int durMed: 450
|
||||
readonly property int durLong: 600
|
||||
|
||||
readonly property int slidePx: 80
|
||||
|
||||
readonly property var emphasized: [0.05, 0.00, 0.133333, 0.06, 0.166667, 0.40, 0.208333, 0.82, 0.25, 1.00, 1.00, 1.00]
|
||||
|
||||
readonly property var emphasizedDecel: [0.05, 0.70, 0.10, 1.00, 1.00, 1.00]
|
||||
|
||||
readonly property var emphasizedAccel: [0.30, 0.00, 0.80, 0.15, 1.00, 1.00]
|
||||
|
||||
readonly property var standard: [0.20, 0.00, 0.00, 1.00, 1.00, 1.00]
|
||||
readonly property var standardDecel: [0.00, 0.00, 0.00, 1.00, 1.00, 1.00]
|
||||
readonly property var standardAccel: [0.30, 0.00, 1.00, 1.00, 1.00, 1.00]
|
||||
}
|
||||
127
quickshell/Common/AppUsageHistoryData.qml
Normal file
127
quickshell/Common/AppUsageHistoryData.qml
Normal file
@@ -0,0 +1,127 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
|
||||
id: root
|
||||
|
||||
property var appUsageRanking: {
|
||||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
loadSettings()
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
|
||||
function parseSettings(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
var settings = JSON.parse(content)
|
||||
appUsageRanking = settings.appUsageRanking || {}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
settingsFile.setText(JSON.stringify({
|
||||
"appUsageRanking": appUsageRanking
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
function addAppUsage(app) {
|
||||
if (!app)
|
||||
return
|
||||
|
||||
var appId = app.id || (app.execString || app.exec || "")
|
||||
if (!appId)
|
||||
return
|
||||
|
||||
var currentRanking = Object.assign({}, appUsageRanking)
|
||||
|
||||
if (currentRanking[appId]) {
|
||||
currentRanking[appId].usageCount = (currentRanking[appId].usageCount
|
||||
|| 1) + 1
|
||||
currentRanking[appId].lastUsed = Date.now()
|
||||
currentRanking[appId].icon = app.icon || currentRanking[appId].icon
|
||||
|| "application-x-executable"
|
||||
currentRanking[appId].name = app.name
|
||||
|| currentRanking[appId].name || ""
|
||||
} else {
|
||||
currentRanking[appId] = {
|
||||
"name": app.name || "",
|
||||
"exec": app.execString || app.exec || "",
|
||||
"icon": app.icon || "application-x-executable",
|
||||
"comment": app.comment || "",
|
||||
"usageCount": 1,
|
||||
"lastUsed": Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
appUsageRanking = currentRanking
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getRankedApps() {
|
||||
var apps = []
|
||||
for (var appId in appUsageRanking) {
|
||||
var appData = appUsageRanking[appId]
|
||||
apps.push({
|
||||
"id": appId,
|
||||
"name": appData.name,
|
||||
"exec": appData.exec,
|
||||
"icon": appData.icon,
|
||||
"comment": appData.comment,
|
||||
"usageCount": appData.usageCount,
|
||||
"lastUsed": appData.lastUsed
|
||||
})
|
||||
}
|
||||
|
||||
return apps.sort(function (a, b) {
|
||||
if (a.usageCount !== b.usageCount)
|
||||
return b.usageCount - a.usageCount
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
}
|
||||
|
||||
function cleanupAppUsageRanking(availableAppIds) {
|
||||
var currentRanking = Object.assign({}, appUsageRanking)
|
||||
var hasChanges = false
|
||||
|
||||
for (var appId in currentRanking) {
|
||||
if (availableAppIds.indexOf(appId) === -1) {
|
||||
delete currentRanking[appId]
|
||||
hasChanges = true
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
appUsageRanking = currentRanking
|
||||
saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
path: StandardPaths.writableLocation(
|
||||
StandardPaths.GenericStateLocation) + "/DankMaterialShell/appusage.json"
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
watchChanges: true
|
||||
onLoaded: {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
onLoadFailed: error => {}
|
||||
}
|
||||
}
|
||||
66
quickshell/Common/Appearance.qml
Normal file
66
quickshell/Common/Appearance.qml
Normal file
@@ -0,0 +1,66 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property Rounding rounding: Rounding {}
|
||||
readonly property Spacing spacing: Spacing {}
|
||||
readonly property FontSize fontSize: FontSize {}
|
||||
readonly property Anim anim: Anim {}
|
||||
|
||||
component Rounding: QtObject {
|
||||
readonly property int small: 8
|
||||
readonly property int normal: 12
|
||||
readonly property int large: 16
|
||||
readonly property int extraLarge: 24
|
||||
readonly property int full: 1000
|
||||
}
|
||||
|
||||
component Spacing: QtObject {
|
||||
readonly property int small: 4
|
||||
readonly property int normal: 8
|
||||
readonly property int large: 12
|
||||
readonly property int extraLarge: 16
|
||||
readonly property int huge: 24
|
||||
}
|
||||
|
||||
component FontSize: QtObject {
|
||||
readonly property int small: 12
|
||||
readonly property int normal: 14
|
||||
readonly property int large: 16
|
||||
readonly property int extraLarge: 20
|
||||
readonly property int huge: 24
|
||||
}
|
||||
|
||||
component AnimCurves: QtObject {
|
||||
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
|
||||
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
|
||||
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
|
||||
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1
|
||||
/ 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
|
||||
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
|
||||
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
|
||||
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1]
|
||||
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1]
|
||||
readonly property list<real> expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1]
|
||||
}
|
||||
|
||||
component AnimDurations: QtObject {
|
||||
readonly property int quick: 150
|
||||
readonly property int normal: 300
|
||||
readonly property int slow: 500
|
||||
readonly property int extraSlow: 1000
|
||||
readonly property int expressiveFastSpatial: 350
|
||||
readonly property int expressiveDefaultSpatial: 500
|
||||
readonly property int expressiveEffects: 200
|
||||
}
|
||||
|
||||
component Anim: QtObject {
|
||||
readonly property AnimCurves curves: AnimCurves {}
|
||||
readonly property AnimDurations durations: AnimDurations {}
|
||||
}
|
||||
}
|
||||
206
quickshell/Common/CacheData.qml
Normal file
206
quickshell/Common/CacheData.qml
Normal file
@@ -0,0 +1,206 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int cacheConfigVersion: 1
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
|
||||
readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericCacheLocation)
|
||||
readonly property string _stateDir: Paths.strip(_stateUrl)
|
||||
|
||||
property bool _loading: false
|
||||
|
||||
property string wallpaperLastPath: ""
|
||||
property string profileLastPath: ""
|
||||
|
||||
property var fileBrowserSettings: ({
|
||||
"wallpaper": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"profile": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_save": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_load": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"generic": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"default": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
}
|
||||
})
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadCache()
|
||||
}
|
||||
}
|
||||
|
||||
function loadCache() {
|
||||
_loading = true
|
||||
parseCache(cacheFile.text())
|
||||
_loading = false
|
||||
}
|
||||
|
||||
function parseCache(content) {
|
||||
_loading = true
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const cache = JSON.parse(content)
|
||||
|
||||
wallpaperLastPath = cache.wallpaperLastPath !== undefined ? cache.wallpaperLastPath : ""
|
||||
profileLastPath = cache.profileLastPath !== undefined ? cache.profileLastPath : ""
|
||||
|
||||
if (cache.fileBrowserSettings !== undefined) {
|
||||
fileBrowserSettings = cache.fileBrowserSettings
|
||||
} else if (cache.fileBrowserViewMode !== undefined) {
|
||||
fileBrowserSettings = {
|
||||
"wallpaper": {
|
||||
"lastPath": cache.wallpaperLastPath || "",
|
||||
"viewMode": cache.fileBrowserViewMode || "grid",
|
||||
"sortBy": cache.fileBrowserSortBy || "name",
|
||||
"sortAscending": cache.fileBrowserSortAscending !== undefined ? cache.fileBrowserSortAscending : true,
|
||||
"iconSizeIndex": cache.fileBrowserIconSizeIndex !== undefined ? cache.fileBrowserIconSizeIndex : 1,
|
||||
"showSidebar": cache.fileBrowserShowSidebar !== undefined ? cache.fileBrowserShowSidebar : true
|
||||
},
|
||||
"profile": {
|
||||
"lastPath": cache.profileLastPath || "",
|
||||
"viewMode": cache.fileBrowserViewMode || "grid",
|
||||
"sortBy": cache.fileBrowserSortBy || "name",
|
||||
"sortAscending": cache.fileBrowserSortAscending !== undefined ? cache.fileBrowserSortAscending : true,
|
||||
"iconSizeIndex": cache.fileBrowserIconSizeIndex !== undefined ? cache.fileBrowserIconSizeIndex : 1,
|
||||
"showSidebar": cache.fileBrowserShowSidebar !== undefined ? cache.fileBrowserShowSidebar : true
|
||||
},
|
||||
"file": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.configVersion === undefined) {
|
||||
migrateFromUndefinedToV1(cache)
|
||||
cleanupUnusedKeys()
|
||||
saveCache()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to parse cache:", e.message)
|
||||
} finally {
|
||||
_loading = false
|
||||
}
|
||||
}
|
||||
|
||||
function saveCache() {
|
||||
if (_loading)
|
||||
return
|
||||
cacheFile.setText(JSON.stringify({
|
||||
"wallpaperLastPath": wallpaperLastPath,
|
||||
"profileLastPath": profileLastPath,
|
||||
"fileBrowserSettings": fileBrowserSettings,
|
||||
"configVersion": cacheConfigVersion
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
function migrateFromUndefinedToV1(cache) {
|
||||
console.info("CacheData: Migrating configuration from undefined to version 1")
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
const validKeys = [
|
||||
"wallpaperLastPath",
|
||||
"profileLastPath",
|
||||
"fileBrowserSettings",
|
||||
"configVersion"
|
||||
]
|
||||
|
||||
try {
|
||||
const content = cacheFile.text()
|
||||
if (!content || !content.trim()) return
|
||||
|
||||
const cache = JSON.parse(content)
|
||||
let needsSave = false
|
||||
|
||||
for (const key in cache) {
|
||||
if (!validKeys.includes(key)) {
|
||||
console.log("CacheData: Removing unused key:", key)
|
||||
delete cache[key]
|
||||
needsSave = true
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
cacheFile.setText(JSON.stringify(cache, null, 2))
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to cleanup unused keys:", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: cacheFile
|
||||
|
||||
path: isGreeterMode ? "" : _stateDir + "/DankMaterialShell/cache.json"
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parseCache(cacheFile.text())
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode) {
|
||||
console.info("CacheData: No cache file found, starting fresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
quickshell/Common/CacheUtils.qml
Normal file
45
quickshell/Common/CacheUtils.qml
Normal file
@@ -0,0 +1,45 @@
|
||||
import Quickshell
|
||||
pragma Singleton
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Clear all image cache
|
||||
function clearImageCache() {
|
||||
Quickshell.execDetached(["rm", "-rf", Paths.stringify(
|
||||
Paths.imagecache)])
|
||||
Paths.mkdir(Paths.imagecache)
|
||||
}
|
||||
|
||||
// Clear cache older than specified minutes
|
||||
function clearOldCache(ageInMinutes) {
|
||||
Quickshell.execDetached(
|
||||
["find", Paths.stringify(
|
||||
Paths.imagecache), "-name", "*.png", "-mmin", `+${ageInMinutes}`, "-delete"])
|
||||
}
|
||||
|
||||
// Clear cache for specific size
|
||||
function clearCacheForSize(size) {
|
||||
Quickshell.execDetached(
|
||||
["find", Paths.stringify(
|
||||
Paths.imagecache), "-name", `*@${size}x${size}.png`, "-delete"])
|
||||
}
|
||||
|
||||
// Get cache size in MB
|
||||
function getCacheSize(callback) {
|
||||
var process = Qt.createQmlObject(`
|
||||
import Quickshell.Io
|
||||
Process {
|
||||
command: ["du", "-sm", "${Paths.stringify(
|
||||
Paths.imagecache)}"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var sizeMB = parseInt(text.split("\\t")[0]) || 0
|
||||
callback(sizeMB)
|
||||
}
|
||||
}
|
||||
}
|
||||
`, root)
|
||||
}
|
||||
}
|
||||
62
quickshell/Common/DankSocket.qml
Normal file
62
quickshell/Common/DankSocket.qml
Normal file
@@ -0,0 +1,62 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias path: socket.path
|
||||
property alias parser: socket.parser
|
||||
property bool connected: false
|
||||
|
||||
property int reconnectBaseMs: 400
|
||||
property int reconnectMaxMs: 15000
|
||||
|
||||
property int _reconnectAttempt: 0
|
||||
|
||||
signal connectionStateChanged()
|
||||
|
||||
onConnectedChanged: {
|
||||
socket.connected = connected
|
||||
}
|
||||
|
||||
Socket {
|
||||
id: socket
|
||||
|
||||
onConnectionStateChanged: {
|
||||
root.connectionStateChanged()
|
||||
if (connected) {
|
||||
root._reconnectAttempt = 0
|
||||
return
|
||||
}
|
||||
if (root.connected) {
|
||||
root._scheduleReconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: reconnectTimer
|
||||
interval: 0
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
socket.connected = false
|
||||
Qt.callLater(() => socket.connected = true)
|
||||
}
|
||||
}
|
||||
|
||||
function send(data) {
|
||||
const json = typeof data === "string" ? data : JSON.stringify(data)
|
||||
const message = json.endsWith("\n") ? json : json + "\n"
|
||||
socket.write(message)
|
||||
socket.flush()
|
||||
}
|
||||
|
||||
function _scheduleReconnect() {
|
||||
const pow = Math.min(_reconnectAttempt, 10)
|
||||
const base = Math.min(reconnectBaseMs * Math.pow(2, pow), reconnectMaxMs)
|
||||
const jitter = Math.floor(Math.random() * Math.floor(base / 4))
|
||||
reconnectTimer.interval = base + jitter
|
||||
reconnectTimer.restart()
|
||||
_reconnectAttempt++
|
||||
}
|
||||
}
|
||||
53
quickshell/Common/Facts.qml
Normal file
53
quickshell/Common/Facts.qml
Normal file
@@ -0,0 +1,53 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property var facts: [
|
||||
"A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.",
|
||||
"A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.",
|
||||
"Right now, 100 trillion solar neutrinos are passing through your body every second.",
|
||||
"The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.",
|
||||
"The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.",
|
||||
"There's a nebula out there that's actually colder than empty space itself.",
|
||||
"We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.",
|
||||
"Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.",
|
||||
"Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.",
|
||||
"Distant galaxies can move away from us faster than light because space itself is stretching.",
|
||||
"The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.",
|
||||
"The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.",
|
||||
"A day on Venus lasts longer than its entire year around the Sun.",
|
||||
"On Mercury, the time between sunrises is 176 Earth days long.",
|
||||
"In about 4.5 billion years, our galaxy will smash into Andromeda.",
|
||||
"Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.",
|
||||
"PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.",
|
||||
"Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.",
|
||||
"Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.",
|
||||
"Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.",
|
||||
"Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.",
|
||||
"Counting to a billion at one number per second would take over 31 years.",
|
||||
"Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.",
|
||||
"Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.",
|
||||
"Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.",
|
||||
"Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.",
|
||||
"Even at light-speed, you'd never catch up to most galaxies—space expands faster.",
|
||||
"Only around 5% of galaxies are ever reachable—even at light-speed.",
|
||||
"If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.",
|
||||
"If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.",
|
||||
"Our oldest radio signals will reach the Milky Way's center in 26,000 years.",
|
||||
"Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.",
|
||||
"The Moon moves 3.8 centimeters farther from Earth every year.",
|
||||
"The universe creates 275 million new stars every single day.",
|
||||
"Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.",
|
||||
"If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.",
|
||||
"The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."
|
||||
]
|
||||
|
||||
function getRandomFact() {
|
||||
return facts[Math.floor(Math.random() * facts.length)]
|
||||
}
|
||||
}
|
||||
113
quickshell/Common/I18n.qml
Normal file
113
quickshell/Common/I18n.qml
Normal file
@@ -0,0 +1,113 @@
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string _rawLocale: Qt.locale().name
|
||||
readonly property string _lang: _rawLocale.split(/[_-]/)[0]
|
||||
readonly property var _candidates: {
|
||||
const fullUnderscore = _rawLocale;
|
||||
const fullHyphen = _rawLocale.replace("_", "-");
|
||||
return [fullUnderscore, fullHyphen, _lang].filter(c => c && c !== "en");
|
||||
}
|
||||
|
||||
|
||||
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
|
||||
|
||||
property string currentLocale: "en"
|
||||
property var translations: ({})
|
||||
property bool translationsLoaded: false
|
||||
|
||||
property url _selectedPath: ""
|
||||
|
||||
FolderListModel {
|
||||
id: dir
|
||||
folder: root.translationsFolder
|
||||
nameFilters: ["*.json"]
|
||||
showDirs: false
|
||||
showDotAndDotDot: false
|
||||
|
||||
onStatusChanged: if (status === FolderListModel.Ready) root._pickTranslation()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: translationLoader
|
||||
path: root._selectedPath
|
||||
|
||||
onLoaded: {
|
||||
try {
|
||||
root.translations = JSON.parse(text())
|
||||
root.translationsLoaded = true
|
||||
console.info(`I18n: Loaded translations for '${root.currentLocale}' ` +
|
||||
`(${Object.keys(root.translations).length} contexts)`)
|
||||
} catch (e) {
|
||||
console.warn(`I18n: Error parsing '${root.currentLocale}':`, e,
|
||||
"- falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
}
|
||||
}
|
||||
|
||||
onLoadFailed: (error) => {
|
||||
console.warn(`I18n: Failed to load '${root.currentLocale}' (${error}), ` +
|
||||
"falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
}
|
||||
}
|
||||
|
||||
function _pickTranslation() {
|
||||
const present = new Set()
|
||||
for (let i = 0; i < dir.count; i++) {
|
||||
const name = dir.get(i, "fileName") // e.g. "zh_CN.json"
|
||||
if (name && name.endsWith(".json")) {
|
||||
present.add(name.slice(0, -5))
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < _candidates.length; i++) {
|
||||
const cand = _candidates[i]
|
||||
if (present.has(cand)) {
|
||||
_useLocale(cand, dir.folder + "/" + cand + ".json")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_fallbackToEnglish()
|
||||
}
|
||||
|
||||
function _useLocale(localeTag, fileUrl) {
|
||||
currentLocale = localeTag
|
||||
_selectedPath = fileUrl
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`)
|
||||
}
|
||||
|
||||
function _fallbackToEnglish() {
|
||||
currentLocale = "en"
|
||||
_selectedPath = ""
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.warn("I18n: Falling back to built-in English strings")
|
||||
}
|
||||
|
||||
function tr(term, context) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
const ctx = context || term
|
||||
if (translations[ctx] && translations[ctx][term]) return translations[ctx][term]
|
||||
for (const c in translations) {
|
||||
if (translations[c] && translations[c][term]) return translations[c][term]
|
||||
}
|
||||
return term
|
||||
}
|
||||
|
||||
function trContext(context, term) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
if (translations[context] && translations[context][term]) return translations[context][term]
|
||||
return term
|
||||
}
|
||||
}
|
||||
16
quickshell/Common/ModalManager.qml
Normal file
16
quickshell/Common/ModalManager.qml
Normal file
@@ -0,0 +1,16 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: modalManager
|
||||
|
||||
signal closeAllModalsExcept(var excludedModal)
|
||||
|
||||
function openModal(modal) {
|
||||
if (!modal.allowStacking) {
|
||||
closeAllModalsExcept(modal)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
quickshell/Common/Paths.qml
Normal file
65
quickshell/Common/Paths.qml
Normal file
@@ -0,0 +1,65 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import QtCore
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property url home: StandardPaths.standardLocations(
|
||||
StandardPaths.HomeLocation)[0]
|
||||
readonly property url pictures: StandardPaths.standardLocations(
|
||||
StandardPaths.PicturesLocation)[0]
|
||||
|
||||
readonly property url data: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericDataLocation)[0]}/DankMaterialShell`
|
||||
readonly property url state: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericStateLocation)[0]}/DankMaterialShell`
|
||||
readonly property url cache: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericCacheLocation)[0]}/DankMaterialShell`
|
||||
readonly property url config: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericConfigLocation)[0]}/DankMaterialShell`
|
||||
|
||||
readonly property url imagecache: `${cache}/imagecache`
|
||||
|
||||
function stringify(path: url): string {
|
||||
return path.toString().replace(/%20/g, " ")
|
||||
}
|
||||
|
||||
function expandTilde(path: string): string {
|
||||
return strip(path.replace("~", stringify(root.home)))
|
||||
}
|
||||
|
||||
function shortenHome(path: string): string {
|
||||
return path.replace(strip(root.home), "~")
|
||||
}
|
||||
|
||||
function strip(path: url): string {
|
||||
return stringify(path).replace("file://", "")
|
||||
}
|
||||
|
||||
function toFileUrl(path: string): string {
|
||||
return path.startsWith("file://") ? path : "file://" + path
|
||||
}
|
||||
|
||||
function mkdir(path: url): void {
|
||||
Quickshell.execDetached(["mkdir", "-p", strip(path)])
|
||||
}
|
||||
|
||||
function copy(from: url, to: url): void {
|
||||
Quickshell.execDetached(["cp", strip(from), strip(to)])
|
||||
}
|
||||
|
||||
// ! Spotify and maybe some other apps report the wrong app id in toplevels, hardcode special case
|
||||
function moddedAppId(appId: string): string {
|
||||
if (appId === "Spotify")
|
||||
return "spotify"
|
||||
if (appId === "beepertexts")
|
||||
return "beeper"
|
||||
if (appId === "home assistant desktop")
|
||||
return "homeassistant-desktop"
|
||||
if (appId.includes("com.transmissionbt.transmission"))
|
||||
return "transmission-gtk"
|
||||
return appId
|
||||
}
|
||||
}
|
||||
110
quickshell/Common/Proc.qml
Normal file
110
quickshell/Common/Proc.qml
Normal file
@@ -0,0 +1,110 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property int defaultDebounceMs: 50
|
||||
property int defaultTimeoutMs: 10000
|
||||
property var _procDebouncers: ({})
|
||||
|
||||
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
||||
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs
|
||||
const timeout = (typeof timeoutMs === "number" && timeoutMs > 0) ? timeoutMs : defaultTimeoutMs
|
||||
let procId = id ? id : Math.random()
|
||||
const isRandomId = !id
|
||||
|
||||
if (!_procDebouncers[procId]) {
|
||||
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
||||
t.triggered.connect(function() { _launchProc(procId, isRandomId) })
|
||||
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout, isRandomId: isRandomId }
|
||||
} else {
|
||||
_procDebouncers[procId].command = command
|
||||
_procDebouncers[procId].callback = callback
|
||||
_procDebouncers[procId].waitMs = wait
|
||||
_procDebouncers[procId].timeoutMs = timeout
|
||||
}
|
||||
|
||||
const entry = _procDebouncers[procId]
|
||||
entry.timer.interval = entry.waitMs
|
||||
entry.timer.restart()
|
||||
}
|
||||
|
||||
function _launchProc(id, isRandomId) {
|
||||
const entry = _procDebouncers[id]
|
||||
if (!entry) return
|
||||
|
||||
const proc = Qt.createQmlObject('import Quickshell.Io; Process { running: false }', root)
|
||||
const out = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
||||
const err = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
||||
const timeoutTimer = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
||||
|
||||
proc.stdout = out
|
||||
proc.stderr = err
|
||||
proc.command = entry.command
|
||||
|
||||
let capturedOut = ""
|
||||
let capturedErr = ""
|
||||
let exitSeen = false
|
||||
let exitCodeValue = -1
|
||||
let outSeen = false
|
||||
let errSeen = false
|
||||
let timedOut = false
|
||||
|
||||
timeoutTimer.interval = entry.timeoutMs
|
||||
timeoutTimer.triggered.connect(function() {
|
||||
if (!exitSeen) {
|
||||
timedOut = true
|
||||
proc.running = false
|
||||
exitSeen = true
|
||||
exitCodeValue = 124
|
||||
maybeComplete()
|
||||
}
|
||||
})
|
||||
|
||||
out.streamFinished.connect(function() {
|
||||
capturedOut = out.text || ""
|
||||
outSeen = true
|
||||
maybeComplete()
|
||||
})
|
||||
|
||||
err.streamFinished.connect(function() {
|
||||
capturedErr = err.text || ""
|
||||
errSeen = true
|
||||
maybeComplete()
|
||||
})
|
||||
|
||||
proc.exited.connect(function(code) {
|
||||
timeoutTimer.stop()
|
||||
exitSeen = true
|
||||
exitCodeValue = code
|
||||
maybeComplete()
|
||||
})
|
||||
|
||||
function maybeComplete() {
|
||||
if (!exitSeen || !outSeen || !errSeen) return
|
||||
timeoutTimer.stop()
|
||||
if (typeof entry.callback === "function") {
|
||||
try { entry.callback(capturedOut, exitCodeValue) } catch (e) { console.warn("runCommand callback error:", e) }
|
||||
}
|
||||
try { proc.destroy() } catch (_) {}
|
||||
try { timeoutTimer.destroy() } catch (_) {}
|
||||
|
||||
if (isRandomId || entry.isRandomId) {
|
||||
Qt.callLater(function() {
|
||||
if (_procDebouncers[id]) {
|
||||
try { _procDebouncers[id].timer.destroy() } catch (_) {}
|
||||
delete _procDebouncers[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
proc.running = true
|
||||
timeoutTimer.start()
|
||||
}
|
||||
}
|
||||
9
quickshell/Common/Ref.qml
Normal file
9
quickshell/Common/Ref.qml
Normal file
@@ -0,0 +1,9 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
QtObject {
|
||||
required property Singleton service
|
||||
|
||||
Component.onCompleted: service.refCount++
|
||||
Component.onDestruction: service.refCount--
|
||||
}
|
||||
975
quickshell/Common/SessionData.qml
Normal file
975
quickshell/Common/SessionData.qml
Normal file
@@ -0,0 +1,975 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int sessionConfigVersion: 1
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
property bool hasTriedDefaultSession: false
|
||||
readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation)
|
||||
readonly property string _stateDir: Paths.strip(_stateUrl)
|
||||
|
||||
property bool isLightMode: false
|
||||
property bool doNotDisturb: false
|
||||
property bool isSwitchingMode: false
|
||||
|
||||
property string wallpaperPath: ""
|
||||
property bool perMonitorWallpaper: false
|
||||
property var monitorWallpapers: ({})
|
||||
property bool perModeWallpaper: false
|
||||
property string wallpaperPathLight: ""
|
||||
property string wallpaperPathDark: ""
|
||||
property var monitorWallpapersLight: ({})
|
||||
property var monitorWallpapersDark: ({})
|
||||
property string wallpaperTransition: "fade"
|
||||
readonly property var availableWallpaperTransitions: ["none", "fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"]
|
||||
property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none")
|
||||
|
||||
property bool wallpaperCyclingEnabled: false
|
||||
property string wallpaperCyclingMode: "interval"
|
||||
property int wallpaperCyclingInterval: 300
|
||||
property string wallpaperCyclingTime: "06:00"
|
||||
property var monitorCyclingSettings: ({})
|
||||
|
||||
property bool nightModeEnabled: false
|
||||
property int nightModeTemperature: 4500
|
||||
property int nightModeHighTemperature: 6500
|
||||
property bool nightModeAutoEnabled: false
|
||||
property string nightModeAutoMode: "time"
|
||||
property int nightModeStartHour: 18
|
||||
property int nightModeStartMinute: 0
|
||||
property int nightModeEndHour: 6
|
||||
property int nightModeEndMinute: 0
|
||||
property real latitude: 0.0
|
||||
property real longitude: 0.0
|
||||
property bool nightModeUseIPLocation: false
|
||||
property string nightModeLocationProvider: ""
|
||||
|
||||
property var pinnedApps: []
|
||||
property var hiddenTrayIds: []
|
||||
property var recentColors: []
|
||||
property bool showThirdPartyPlugins: false
|
||||
property string launchPrefix: ""
|
||||
property string lastBrightnessDevice: ""
|
||||
property var brightnessExponentialDevices: ({})
|
||||
property var brightnessUserSetValues: ({})
|
||||
property var brightnessExponentValues: ({})
|
||||
|
||||
property int selectedGpuIndex: 0
|
||||
property bool nvidiaGpuTempEnabled: false
|
||||
property bool nonNvidiaGpuTempEnabled: false
|
||||
property var enabledGpuPciIds: []
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadSettings()
|
||||
}
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
if (isGreeterMode) {
|
||||
parseSettings(greeterSessionFile.text())
|
||||
} else {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
}
|
||||
|
||||
function parseSettings(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
var settings = JSON.parse(content)
|
||||
isLightMode = settings.isLightMode !== undefined ? settings.isLightMode : false
|
||||
|
||||
if (settings.wallpaperPath && settings.wallpaperPath.startsWith("we:")) {
|
||||
console.warn("WallpaperEngine wallpaper detected, resetting wallpaper")
|
||||
wallpaperPath = ""
|
||||
Quickshell.execDetached([
|
||||
"notify-send",
|
||||
"-u", "critical",
|
||||
"-a", "DMS",
|
||||
"-i", "dialog-warning",
|
||||
"WallpaperEngine Support Moved",
|
||||
"WallpaperEngine support has been moved to a plugin. Please enable the Linux Wallpaper Engine plugin in Settings → Plugins to continue using WallpaperEngine."
|
||||
])
|
||||
} else {
|
||||
wallpaperPath = settings.wallpaperPath !== undefined ? settings.wallpaperPath : ""
|
||||
}
|
||||
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false
|
||||
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {}
|
||||
perModeWallpaper = settings.perModeWallpaper !== undefined ? settings.perModeWallpaper : false
|
||||
wallpaperPathLight = settings.wallpaperPathLight !== undefined ? settings.wallpaperPathLight : ""
|
||||
wallpaperPathDark = settings.wallpaperPathDark !== undefined ? settings.wallpaperPathDark : ""
|
||||
monitorWallpapersLight = settings.monitorWallpapersLight !== undefined ? settings.monitorWallpapersLight : {}
|
||||
monitorWallpapersDark = settings.monitorWallpapersDark !== undefined ? settings.monitorWallpapersDark : {}
|
||||
brightnessExponentialDevices = settings.brightnessExponentialDevices !== undefined ? settings.brightnessExponentialDevices : (settings.brightnessLogarithmicDevices || {})
|
||||
brightnessUserSetValues = settings.brightnessUserSetValues !== undefined ? settings.brightnessUserSetValues : {}
|
||||
brightnessExponentValues = settings.brightnessExponentValues !== undefined ? settings.brightnessExponentValues : {}
|
||||
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
|
||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
|
||||
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500
|
||||
nightModeHighTemperature = settings.nightModeHighTemperature !== undefined ? settings.nightModeHighTemperature : 6500
|
||||
nightModeAutoEnabled = settings.nightModeAutoEnabled !== undefined ? settings.nightModeAutoEnabled : false
|
||||
nightModeAutoMode = settings.nightModeAutoMode !== undefined ? settings.nightModeAutoMode : "time"
|
||||
if (settings.nightModeStartTime !== undefined) {
|
||||
const parts = settings.nightModeStartTime.split(":")
|
||||
nightModeStartHour = parseInt(parts[0]) || 18
|
||||
nightModeStartMinute = parseInt(parts[1]) || 0
|
||||
} else {
|
||||
nightModeStartHour = settings.nightModeStartHour !== undefined ? settings.nightModeStartHour : 18
|
||||
nightModeStartMinute = settings.nightModeStartMinute !== undefined ? settings.nightModeStartMinute : 0
|
||||
}
|
||||
if (settings.nightModeEndTime !== undefined) {
|
||||
const parts = settings.nightModeEndTime.split(":")
|
||||
nightModeEndHour = parseInt(parts[0]) || 6
|
||||
nightModeEndMinute = parseInt(parts[1]) || 0
|
||||
} else {
|
||||
nightModeEndHour = settings.nightModeEndHour !== undefined ? settings.nightModeEndHour : 6
|
||||
nightModeEndMinute = settings.nightModeEndMinute !== undefined ? settings.nightModeEndMinute : 0
|
||||
}
|
||||
latitude = settings.latitude !== undefined ? settings.latitude : 0.0
|
||||
longitude = settings.longitude !== undefined ? settings.longitude : 0.0
|
||||
nightModeUseIPLocation = settings.nightModeUseIPLocation !== undefined ? settings.nightModeUseIPLocation : false
|
||||
nightModeLocationProvider = settings.nightModeLocationProvider !== undefined ? settings.nightModeLocationProvider : ""
|
||||
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
|
||||
hiddenTrayIds = settings.hiddenTrayIds !== undefined ? settings.hiddenTrayIds : []
|
||||
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
|
||||
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false
|
||||
nonNvidiaGpuTempEnabled = settings.nonNvidiaGpuTempEnabled !== undefined ? settings.nonNvidiaGpuTempEnabled : false
|
||||
enabledGpuPciIds = settings.enabledGpuPciIds !== undefined ? settings.enabledGpuPciIds : []
|
||||
wallpaperCyclingEnabled = settings.wallpaperCyclingEnabled !== undefined ? settings.wallpaperCyclingEnabled : false
|
||||
wallpaperCyclingMode = settings.wallpaperCyclingMode !== undefined ? settings.wallpaperCyclingMode : "interval"
|
||||
wallpaperCyclingInterval = settings.wallpaperCyclingInterval !== undefined ? settings.wallpaperCyclingInterval : 300
|
||||
wallpaperCyclingTime = settings.wallpaperCyclingTime !== undefined ? settings.wallpaperCyclingTime : "06:00"
|
||||
monitorCyclingSettings = settings.monitorCyclingSettings !== undefined ? settings.monitorCyclingSettings : {}
|
||||
lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : ""
|
||||
launchPrefix = settings.launchPrefix !== undefined ? settings.launchPrefix : ""
|
||||
wallpaperTransition = settings.wallpaperTransition !== undefined ? settings.wallpaperTransition : "fade"
|
||||
includedTransitions = settings.includedTransitions !== undefined ? settings.includedTransitions : availableWallpaperTransitions.filter(t => t !== "none")
|
||||
recentColors = settings.recentColors !== undefined ? settings.recentColors : []
|
||||
showThirdPartyPlugins = settings.showThirdPartyPlugins !== undefined ? settings.showThirdPartyPlugins : false
|
||||
|
||||
if (settings.configVersion === undefined) {
|
||||
migrateFromUndefinedToV1(settings)
|
||||
saveSettings()
|
||||
} else if (settings.configVersion === sessionConfigVersion) {
|
||||
cleanupUnusedKeys()
|
||||
}
|
||||
|
||||
if (!isGreeterMode) {
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof WallpaperCyclingService !== "undefined") {
|
||||
WallpaperCyclingService.updateCyclingState()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
if (isGreeterMode)
|
||||
return
|
||||
settingsFile.setText(JSON.stringify({
|
||||
"isLightMode": isLightMode,
|
||||
"wallpaperPath": wallpaperPath,
|
||||
"perMonitorWallpaper": perMonitorWallpaper,
|
||||
"monitorWallpapers": monitorWallpapers,
|
||||
"perModeWallpaper": perModeWallpaper,
|
||||
"wallpaperPathLight": wallpaperPathLight,
|
||||
"wallpaperPathDark": wallpaperPathDark,
|
||||
"monitorWallpapersLight": monitorWallpapersLight,
|
||||
"monitorWallpapersDark": monitorWallpapersDark,
|
||||
"brightnessExponentialDevices": brightnessExponentialDevices,
|
||||
"brightnessUserSetValues": brightnessUserSetValues,
|
||||
"brightnessExponentValues": brightnessExponentValues,
|
||||
"doNotDisturb": doNotDisturb,
|
||||
"nightModeEnabled": nightModeEnabled,
|
||||
"nightModeTemperature": nightModeTemperature,
|
||||
"nightModeHighTemperature": nightModeHighTemperature,
|
||||
"nightModeAutoEnabled": nightModeAutoEnabled,
|
||||
"nightModeAutoMode": nightModeAutoMode,
|
||||
"nightModeStartHour": nightModeStartHour,
|
||||
"nightModeStartMinute": nightModeStartMinute,
|
||||
"nightModeEndHour": nightModeEndHour,
|
||||
"nightModeEndMinute": nightModeEndMinute,
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"nightModeUseIPLocation": nightModeUseIPLocation,
|
||||
"nightModeLocationProvider": nightModeLocationProvider,
|
||||
"pinnedApps": pinnedApps,
|
||||
"hiddenTrayIds": hiddenTrayIds,
|
||||
"selectedGpuIndex": selectedGpuIndex,
|
||||
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
|
||||
"nonNvidiaGpuTempEnabled": nonNvidiaGpuTempEnabled,
|
||||
"enabledGpuPciIds": enabledGpuPciIds,
|
||||
"wallpaperCyclingEnabled": wallpaperCyclingEnabled,
|
||||
"wallpaperCyclingMode": wallpaperCyclingMode,
|
||||
"wallpaperCyclingInterval": wallpaperCyclingInterval,
|
||||
"wallpaperCyclingTime": wallpaperCyclingTime,
|
||||
"monitorCyclingSettings": monitorCyclingSettings,
|
||||
"lastBrightnessDevice": lastBrightnessDevice,
|
||||
"launchPrefix": launchPrefix,
|
||||
"wallpaperTransition": wallpaperTransition,
|
||||
"includedTransitions": includedTransitions,
|
||||
"recentColors": recentColors,
|
||||
"showThirdPartyPlugins": showThirdPartyPlugins,
|
||||
"configVersion": sessionConfigVersion
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
function migrateFromUndefinedToV1(settings) {
|
||||
console.info("SessionData: Migrating configuration from undefined to version 1")
|
||||
if (typeof SettingsData !== "undefined") {
|
||||
if (settings.acMonitorTimeout !== undefined) {
|
||||
SettingsData.set("acMonitorTimeout", settings.acMonitorTimeout)
|
||||
}
|
||||
if (settings.acLockTimeout !== undefined) {
|
||||
SettingsData.set("acLockTimeout", settings.acLockTimeout)
|
||||
}
|
||||
if (settings.acSuspendTimeout !== undefined) {
|
||||
SettingsData.set("acSuspendTimeout", settings.acSuspendTimeout)
|
||||
}
|
||||
if (settings.acHibernateTimeout !== undefined) {
|
||||
SettingsData.set("acHibernateTimeout", settings.acHibernateTimeout)
|
||||
}
|
||||
if (settings.batteryMonitorTimeout !== undefined) {
|
||||
SettingsData.set("batteryMonitorTimeout", settings.batteryMonitorTimeout)
|
||||
}
|
||||
if (settings.batteryLockTimeout !== undefined) {
|
||||
SettingsData.set("batteryLockTimeout", settings.batteryLockTimeout)
|
||||
}
|
||||
if (settings.batterySuspendTimeout !== undefined) {
|
||||
SettingsData.set("batterySuspendTimeout", settings.batterySuspendTimeout)
|
||||
}
|
||||
if (settings.batteryHibernateTimeout !== undefined) {
|
||||
SettingsData.set("batteryHibernateTimeout", settings.batteryHibernateTimeout)
|
||||
}
|
||||
if (settings.lockBeforeSuspend !== undefined) {
|
||||
SettingsData.set("lockBeforeSuspend", settings.lockBeforeSuspend)
|
||||
}
|
||||
if (settings.loginctlLockIntegration !== undefined) {
|
||||
SettingsData.set("loginctlLockIntegration", settings.loginctlLockIntegration)
|
||||
}
|
||||
if (settings.launchPrefix !== undefined) {
|
||||
SettingsData.set("launchPrefix", settings.launchPrefix)
|
||||
}
|
||||
}
|
||||
if (typeof CacheData !== "undefined") {
|
||||
if (settings.wallpaperLastPath !== undefined) {
|
||||
CacheData.wallpaperLastPath = settings.wallpaperLastPath
|
||||
}
|
||||
if (settings.profileLastPath !== undefined) {
|
||||
CacheData.profileLastPath = settings.profileLastPath
|
||||
}
|
||||
CacheData.saveCache()
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
const validKeys = ["isLightMode", "wallpaperPath", "perMonitorWallpaper", "monitorWallpapers", "perModeWallpaper", "wallpaperPathLight", "wallpaperPathDark", "monitorWallpapersLight", "monitorWallpapersDark", "doNotDisturb", "nightModeEnabled", "nightModeTemperature", "nightModeHighTemperature", "nightModeAutoEnabled", "nightModeAutoMode", "nightModeStartHour", "nightModeStartMinute", "nightModeEndHour", "nightModeEndMinute", "latitude", "longitude", "nightModeUseIPLocation", "nightModeLocationProvider", "pinnedApps", "hiddenTrayIds", "selectedGpuIndex", "nvidiaGpuTempEnabled", "nonNvidiaGpuTempEnabled", "enabledGpuPciIds", "wallpaperCyclingEnabled", "wallpaperCyclingMode", "wallpaperCyclingInterval", "wallpaperCyclingTime", "monitorCyclingSettings", "lastBrightnessDevice", "brightnessExponentialDevices", "brightnessUserSetValues", "brightnessExponentValues", "launchPrefix", "wallpaperTransition", "includedTransitions", "recentColors", "showThirdPartyPlugins", "configVersion"]
|
||||
|
||||
try {
|
||||
const content = settingsFile.text()
|
||||
if (!content || !content.trim())
|
||||
return
|
||||
|
||||
const settings = JSON.parse(content)
|
||||
let needsSave = false
|
||||
|
||||
for (const key in settings) {
|
||||
if (!validKeys.includes(key)) {
|
||||
console.log("SessionData: Removing unused key:", key)
|
||||
delete settings[key]
|
||||
needsSave = true
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
settingsFile.setText(JSON.stringify(settings, null, 2))
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SessionData: Failed to cleanup unused keys:", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
function setLightMode(lightMode) {
|
||||
isSwitchingMode = true
|
||||
isLightMode = lightMode
|
||||
syncWallpaperForCurrentMode()
|
||||
saveSettings()
|
||||
Qt.callLater(() => { isSwitchingMode = false })
|
||||
}
|
||||
|
||||
function setDoNotDisturb(enabled) {
|
||||
doNotDisturb = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaperPath(path) {
|
||||
wallpaperPath = path
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaper(imagePath) {
|
||||
wallpaperPath = imagePath
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
wallpaperPathLight = imagePath
|
||||
} else {
|
||||
wallpaperPathDark = imagePath
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setWallpaperColor(color) {
|
||||
wallpaperPath = color
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
wallpaperPathLight = color
|
||||
} else {
|
||||
wallpaperPathDark = color
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function clearWallpaper() {
|
||||
wallpaperPath = ""
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.theme) {
|
||||
Theme.switchTheme(SettingsData.theme)
|
||||
} else {
|
||||
Theme.switchTheme("blue")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setPerMonitorWallpaper(enabled) {
|
||||
perMonitorWallpaper = enabled
|
||||
if (enabled && perModeWallpaper) {
|
||||
syncWallpaperForCurrentMode()
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setPerModeWallpaper(enabled) {
|
||||
if (enabled && wallpaperCyclingEnabled) {
|
||||
setWallpaperCyclingEnabled(false)
|
||||
}
|
||||
if (enabled && perMonitorWallpaper) {
|
||||
var monitorCyclingAny = false
|
||||
for (var key in monitorCyclingSettings) {
|
||||
if (monitorCyclingSettings[key].enabled) {
|
||||
monitorCyclingAny = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (monitorCyclingAny) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
for (var screenName in newSettings) {
|
||||
newSettings[screenName].enabled = false
|
||||
}
|
||||
monitorCyclingSettings = newSettings
|
||||
}
|
||||
}
|
||||
|
||||
perModeWallpaper = enabled
|
||||
if (enabled) {
|
||||
if (perMonitorWallpaper) {
|
||||
monitorWallpapersLight = Object.assign({}, monitorWallpapers)
|
||||
monitorWallpapersDark = Object.assign({}, monitorWallpapers)
|
||||
} else {
|
||||
wallpaperPathLight = wallpaperPath
|
||||
wallpaperPathDark = wallpaperPath
|
||||
}
|
||||
} else {
|
||||
syncWallpaperForCurrentMode()
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setMonitorWallpaper(screenName, path) {
|
||||
var newMonitorWallpapers = Object.assign({}, monitorWallpapers)
|
||||
if (path && path !== "") {
|
||||
newMonitorWallpapers[screenName] = path
|
||||
} else {
|
||||
delete newMonitorWallpapers[screenName]
|
||||
}
|
||||
monitorWallpapers = newMonitorWallpapers
|
||||
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
var newLight = Object.assign({}, monitorWallpapersLight)
|
||||
if (path && path !== "") {
|
||||
newLight[screenName] = path
|
||||
} else {
|
||||
delete newLight[screenName]
|
||||
}
|
||||
monitorWallpapersLight = newLight
|
||||
} else {
|
||||
var newDark = Object.assign({}, monitorWallpapersDark)
|
||||
if (path && path !== "") {
|
||||
newDark[screenName] = path
|
||||
} else {
|
||||
delete newDark[screenName]
|
||||
}
|
||||
monitorWallpapersDark = newDark
|
||||
}
|
||||
}
|
||||
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined" && typeof Quickshell !== "undefined" && typeof SettingsData !== "undefined") {
|
||||
var screens = Quickshell.screens
|
||||
if (screens.length > 0) {
|
||||
var targetMonitor = (SettingsData.matugenTargetMonitor && SettingsData.matugenTargetMonitor !== "") ? SettingsData.matugenTargetMonitor : screens[0].name
|
||||
if (screenName === targetMonitor) {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setWallpaperTransition(transition) {
|
||||
wallpaperTransition = transition
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaperCyclingEnabled(enabled) {
|
||||
wallpaperCyclingEnabled = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaperCyclingMode(mode) {
|
||||
wallpaperCyclingMode = mode
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaperCyclingInterval(interval) {
|
||||
wallpaperCyclingInterval = interval
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWallpaperCyclingTime(time) {
|
||||
wallpaperCyclingTime = time
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingEnabled(screenName, enabled) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].enabled = enabled
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingMode(screenName, mode) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].mode = mode
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingInterval(screenName, interval) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].interval = interval
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingTime(screenName, time) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].time = time
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeEnabled(enabled) {
|
||||
nightModeEnabled = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeTemperature(temperature) {
|
||||
nightModeTemperature = temperature
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeHighTemperature(temperature) {
|
||||
nightModeHighTemperature = temperature
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeAutoEnabled(enabled) {
|
||||
console.log("SessionData: Setting nightModeAutoEnabled to", enabled)
|
||||
nightModeAutoEnabled = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeAutoMode(mode) {
|
||||
nightModeAutoMode = mode
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeStartHour(hour) {
|
||||
nightModeStartHour = hour
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeStartMinute(minute) {
|
||||
nightModeStartMinute = minute
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeEndHour(hour) {
|
||||
nightModeEndHour = hour
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeEndMinute(minute) {
|
||||
nightModeEndMinute = minute
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeUseIPLocation(use) {
|
||||
nightModeUseIPLocation = use
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLatitude(lat) {
|
||||
console.log("SessionData: Setting latitude to", lat)
|
||||
latitude = lat
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLongitude(lng) {
|
||||
console.log("SessionData: Setting longitude to", lng)
|
||||
longitude = lng
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNightModeLocationProvider(provider) {
|
||||
nightModeLocationProvider = provider
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setPinnedApps(apps) {
|
||||
pinnedApps = apps
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function addPinnedApp(appId) {
|
||||
if (!appId)
|
||||
return
|
||||
var currentPinned = [...pinnedApps]
|
||||
if (currentPinned.indexOf(appId) === -1) {
|
||||
currentPinned.push(appId)
|
||||
setPinnedApps(currentPinned)
|
||||
}
|
||||
}
|
||||
|
||||
function removePinnedApp(appId) {
|
||||
if (!appId)
|
||||
return
|
||||
var currentPinned = pinnedApps.filter(id => id !== appId)
|
||||
setPinnedApps(currentPinned)
|
||||
}
|
||||
|
||||
function isPinnedApp(appId) {
|
||||
return appId && pinnedApps.indexOf(appId) !== -1
|
||||
}
|
||||
|
||||
function hideTrayId(trayId) {
|
||||
if (!trayId) return
|
||||
const current = [...hiddenTrayIds]
|
||||
if (current.indexOf(trayId) === -1) {
|
||||
current.push(trayId)
|
||||
hiddenTrayIds = current
|
||||
saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
function showTrayId(trayId) {
|
||||
if (!trayId) return
|
||||
hiddenTrayIds = hiddenTrayIds.filter(id => id !== trayId)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function isHiddenTrayId(trayId) {
|
||||
return trayId && hiddenTrayIds.indexOf(trayId) !== -1
|
||||
}
|
||||
|
||||
function addRecentColor(color) {
|
||||
const colorStr = color.toString()
|
||||
let recent = recentColors.slice()
|
||||
recent = recent.filter(c => c !== colorStr)
|
||||
recent.unshift(colorStr)
|
||||
if (recent.length > 5)
|
||||
recent = recent.slice(0, 5)
|
||||
recentColors = recent
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setShowThirdPartyPlugins(enabled) {
|
||||
showThirdPartyPlugins = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLaunchPrefix(prefix) {
|
||||
launchPrefix = prefix
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLastBrightnessDevice(device) {
|
||||
lastBrightnessDevice = device
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setBrightnessExponential(deviceName, enabled) {
|
||||
var newSettings = Object.assign({}, brightnessExponentialDevices)
|
||||
if (enabled) {
|
||||
newSettings[deviceName] = true
|
||||
} else {
|
||||
delete newSettings[deviceName]
|
||||
}
|
||||
brightnessExponentialDevices = newSettings
|
||||
saveSettings()
|
||||
|
||||
if (typeof DisplayService !== "undefined") {
|
||||
DisplayService.updateDeviceBrightnessDisplay(deviceName)
|
||||
}
|
||||
}
|
||||
|
||||
function getBrightnessExponential(deviceName) {
|
||||
return brightnessExponentialDevices[deviceName] === true
|
||||
}
|
||||
|
||||
function setBrightnessUserSetValue(deviceName, value) {
|
||||
var newValues = Object.assign({}, brightnessUserSetValues)
|
||||
newValues[deviceName] = value
|
||||
brightnessUserSetValues = newValues
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getBrightnessUserSetValue(deviceName) {
|
||||
return brightnessUserSetValues[deviceName]
|
||||
}
|
||||
|
||||
function setBrightnessExponent(deviceName, exponent) {
|
||||
var newValues = Object.assign({}, brightnessExponentValues)
|
||||
if (exponent !== undefined && exponent !== null) {
|
||||
newValues[deviceName] = exponent
|
||||
} else {
|
||||
delete newValues[deviceName]
|
||||
}
|
||||
brightnessExponentValues = newValues
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getBrightnessExponent(deviceName) {
|
||||
const value = brightnessExponentValues[deviceName]
|
||||
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()
|
||||
}
|
||||
|
||||
function syncWallpaperForCurrentMode() {
|
||||
if (!perModeWallpaper)
|
||||
return
|
||||
|
||||
if (perMonitorWallpaper) {
|
||||
monitorWallpapers = isLightMode ? Object.assign({}, monitorWallpapersLight) : Object.assign({}, monitorWallpapersDark)
|
||||
return
|
||||
}
|
||||
|
||||
wallpaperPath = isLightMode ? wallpaperPathLight : wallpaperPathDark
|
||||
}
|
||||
|
||||
function getMonitorWallpaper(screenName) {
|
||||
if (!perMonitorWallpaper) {
|
||||
return wallpaperPath
|
||||
}
|
||||
return monitorWallpapers[screenName] || wallpaperPath
|
||||
}
|
||||
|
||||
function getMonitorCyclingSettings(screenName) {
|
||||
return monitorCyclingSettings[screenName] || {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell/session.json"
|
||||
blockLoading: isGreeterMode
|
||||
blockWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parseSettings(settingsFile.text())
|
||||
hasTriedDefaultSession = false
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSession) {
|
||||
hasTriedDefaultSession = true
|
||||
defaultSessionCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: greeterSessionFile
|
||||
|
||||
path: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
return greetCfgDir + "/session.json"
|
||||
}
|
||||
preload: isGreeterMode
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
if (isGreeterMode) {
|
||||
parseSettings(greeterSessionFile.text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: defaultSessionCheckProcess
|
||||
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + _stateDir
|
||||
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-session.json\" ] && [ ! -f \"$CONFIG_DIR/session.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-session.json\" \"$CONFIG_DIR/session.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
console.info("Copied default-session.json to session.json")
|
||||
settingsFile.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
943
quickshell/Common/SettingsData.qml
Normal file
943
quickshell/Common/SettingsData.qml
Normal file
@@ -0,0 +1,943 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Common.settings
|
||||
import qs.Services
|
||||
import "settings/SettingsSpec.js" as Spec
|
||||
import "settings/SettingsStore.js" as Store
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int settingsConfigVersion: 1
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
|
||||
enum Position {
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
enum AnimationSpeed {
|
||||
None,
|
||||
Short,
|
||||
Medium,
|
||||
Long,
|
||||
Custom
|
||||
}
|
||||
|
||||
enum SuspendBehavior {
|
||||
Suspend,
|
||||
Hibernate,
|
||||
SuspendThenHibernate
|
||||
}
|
||||
|
||||
readonly property string defaultFontFamily: "Inter Variable"
|
||||
readonly property string defaultMonoFontFamily: "Fira Code"
|
||||
readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation)
|
||||
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
||||
readonly property string _configDir: Paths.strip(_configUrl)
|
||||
readonly property string pluginSettingsPath: _configDir + "/DankMaterialShell/plugin_settings.json"
|
||||
|
||||
property bool _loading: false
|
||||
property bool _pluginSettingsLoading: false
|
||||
property bool hasTriedDefaultSettings: false
|
||||
property var pluginSettings: ({})
|
||||
|
||||
property alias dankBarLeftWidgetsModel: leftWidgetsModel
|
||||
property alias dankBarCenterWidgetsModel: centerWidgetsModel
|
||||
property alias dankBarRightWidgetsModel: rightWidgetsModel
|
||||
|
||||
property string currentThemeName: "blue"
|
||||
property string customThemeFile: ""
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property bool runUserMatugenTemplates: true
|
||||
property string matugenTargetMonitor: ""
|
||||
property real dankBarTransparency: 1.0
|
||||
property real dankBarWidgetTransparency: 1.0
|
||||
property real popupTransparency: 1.0
|
||||
property real dockTransparency: 1
|
||||
property string widgetBackgroundColor: "sch"
|
||||
property real cornerRadius: 12
|
||||
|
||||
property bool use24HourClock: true
|
||||
property bool showSeconds: false
|
||||
property bool useFahrenheit: false
|
||||
property bool nightModeEnabled: false
|
||||
property int animationSpeed: SettingsData.AnimationSpeed.Short
|
||||
property int customAnimationDuration: 500
|
||||
property string wallpaperFillMode: "Fill"
|
||||
property bool blurredWallpaperLayer: false
|
||||
property bool blurWallpaperOnOverview: false
|
||||
|
||||
property bool showLauncherButton: true
|
||||
property bool showWorkspaceSwitcher: true
|
||||
property bool showFocusedWindow: true
|
||||
property bool showWeather: true
|
||||
property bool showMusic: true
|
||||
property bool showClipboard: true
|
||||
property bool showCpuUsage: true
|
||||
property bool showMemUsage: true
|
||||
property bool showCpuTemp: true
|
||||
property bool showGpuTemp: true
|
||||
property int selectedGpuIndex: 0
|
||||
property var enabledGpuPciIds: []
|
||||
property bool showSystemTray: true
|
||||
property bool showClock: true
|
||||
property bool showNotificationButton: true
|
||||
property bool showBattery: true
|
||||
property bool showControlCenterButton: true
|
||||
|
||||
property bool controlCenterShowNetworkIcon: true
|
||||
property bool controlCenterShowBluetoothIcon: true
|
||||
property bool controlCenterShowAudioIcon: true
|
||||
property var controlCenterWidgets: [{
|
||||
"id": "volumeSlider",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "brightnessSlider",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "wifi",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "bluetooth",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "audioOutput",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "audioInput",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "nightMode",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}, {
|
||||
"id": "darkMode",
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}]
|
||||
|
||||
property bool showWorkspaceIndex: false
|
||||
property bool showWorkspacePadding: false
|
||||
property bool workspaceScrolling: false
|
||||
property bool showWorkspaceApps: false
|
||||
property int maxWorkspaceIcons: 3
|
||||
property bool workspacesPerMonitor: true
|
||||
property bool dwlShowAllTags: false
|
||||
property var workspaceNameIcons: ({})
|
||||
property bool waveProgressEnabled: true
|
||||
property bool clockCompactMode: false
|
||||
property bool focusedWindowCompactMode: false
|
||||
property bool runningAppsCompactMode: true
|
||||
property bool keyboardLayoutNameCompactMode: false
|
||||
property bool runningAppsCurrentWorkspace: false
|
||||
property bool runningAppsGroupByApp: false
|
||||
property string clockDateFormat: ""
|
||||
property string lockDateFormat: ""
|
||||
property int mediaSize: 1
|
||||
|
||||
property var dankBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
property var dankBarCenterWidgets: ["music", "clock", "weather"]
|
||||
property var dankBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
|
||||
property var dankBarWidgetOrder: []
|
||||
|
||||
property string appLauncherViewMode: "list"
|
||||
property string spotlightModalViewMode: "list"
|
||||
property bool sortAppsAlphabetically: false
|
||||
|
||||
property string weatherLocation: "New York, NY"
|
||||
property string weatherCoordinates: "40.7128,-74.0060"
|
||||
property bool useAutoLocation: false
|
||||
property bool weatherEnabled: true
|
||||
|
||||
property string networkPreference: "auto"
|
||||
property string vpnLastConnected: ""
|
||||
|
||||
property string iconTheme: "System Default"
|
||||
property var availableIconThemes: ["System Default"]
|
||||
property string systemDefaultIconTheme: ""
|
||||
property bool qt5ctAvailable: false
|
||||
property bool qt6ctAvailable: false
|
||||
property bool gtkAvailable: false
|
||||
|
||||
property string launcherLogoMode: "apps"
|
||||
property string launcherLogoCustomPath: ""
|
||||
property string launcherLogoColorOverride: ""
|
||||
property bool launcherLogoColorInvertOnMode: false
|
||||
property real launcherLogoBrightness: 0.5
|
||||
property real launcherLogoContrast: 1
|
||||
property int launcherLogoSizeOffset: 0
|
||||
|
||||
property string fontFamily: "Inter Variable"
|
||||
property string monoFontFamily: "Fira Code"
|
||||
property int fontWeight: Font.Normal
|
||||
property real fontScale: 1.0
|
||||
property real dankBarFontScale: 1.0
|
||||
|
||||
property bool notepadUseMonospace: true
|
||||
property string notepadFontFamily: ""
|
||||
property real notepadFontSize: 14
|
||||
property bool notepadShowLineNumbers: false
|
||||
property real notepadTransparencyOverride: -1
|
||||
property real notepadLastCustomTransparency: 0.7
|
||||
|
||||
onNotepadUseMonospaceChanged: saveSettings()
|
||||
onNotepadFontFamilyChanged: saveSettings()
|
||||
onNotepadFontSizeChanged: saveSettings()
|
||||
onNotepadShowLineNumbersChanged: saveSettings()
|
||||
onNotepadTransparencyOverrideChanged: {
|
||||
if (notepadTransparencyOverride > 0) {
|
||||
notepadLastCustomTransparency = notepadTransparencyOverride
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
onNotepadLastCustomTransparencyChanged: saveSettings()
|
||||
|
||||
property bool soundsEnabled: true
|
||||
property bool useSystemSoundTheme: false
|
||||
property bool soundNewNotification: true
|
||||
property bool soundVolumeChanged: true
|
||||
property bool soundPluggedIn: true
|
||||
|
||||
property int acMonitorTimeout: 0
|
||||
property int acLockTimeout: 0
|
||||
property int acSuspendTimeout: 0
|
||||
property int acSuspendBehavior: SettingsData.SuspendBehavior.Suspend
|
||||
property int batteryMonitorTimeout: 0
|
||||
property int batteryLockTimeout: 0
|
||||
property int batterySuspendTimeout: 0
|
||||
property int batterySuspendBehavior: SettingsData.SuspendBehavior.Suspend
|
||||
property bool lockBeforeSuspend: false
|
||||
property bool preventIdleForMedia: false
|
||||
property bool loginctlLockIntegration: true
|
||||
property string launchPrefix: ""
|
||||
property var brightnessDevicePins: ({})
|
||||
|
||||
property bool gtkThemingEnabled: false
|
||||
property bool qtThemingEnabled: false
|
||||
property bool syncModeWithPortal: true
|
||||
|
||||
property bool showDock: false
|
||||
property bool dockAutoHide: false
|
||||
property bool dockGroupByApp: false
|
||||
property bool dockOpenOnOverview: false
|
||||
property int dockPosition: SettingsData.Position.Bottom
|
||||
property real dockSpacing: 4
|
||||
property real dockBottomGap: 0
|
||||
property real dockMargin: 0
|
||||
property real dockIconSize: 40
|
||||
property string dockIndicatorStyle: "circle"
|
||||
|
||||
property bool notificationOverlayEnabled: false
|
||||
property bool dankBarAutoHide: false
|
||||
property bool dankBarOpenOnOverview: false
|
||||
property bool dankBarVisible: true
|
||||
property int overviewRows: 2
|
||||
property int overviewColumns: 5
|
||||
property real overviewScale: 0.16
|
||||
property real dankBarSpacing: 4
|
||||
property real dankBarBottomGap: 0
|
||||
property real dankBarInnerPadding: 4
|
||||
property int dankBarPosition: SettingsData.Position.Top
|
||||
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
||||
|
||||
property bool dankBarSquareCorners: false
|
||||
property bool dankBarNoBackground: false
|
||||
property bool dankBarGothCornersEnabled: false
|
||||
property bool dankBarGothCornerRadiusOverride: false
|
||||
property real dankBarGothCornerRadiusValue: 12
|
||||
property bool dankBarBorderEnabled: false
|
||||
property string dankBarBorderColor: "surfaceText"
|
||||
property real dankBarBorderOpacity: 1.0
|
||||
property real dankBarBorderThickness: 1
|
||||
|
||||
onDankBarGothCornerRadiusOverrideChanged: saveSettings()
|
||||
onDankBarGothCornerRadiusValueChanged: saveSettings()
|
||||
onDankBarBorderColorChanged: saveSettings()
|
||||
onDankBarBorderOpacityChanged: saveSettings()
|
||||
onDankBarBorderThicknessChanged: saveSettings()
|
||||
|
||||
property bool popupGapsAuto: true
|
||||
property int popupGapsManual: 4
|
||||
|
||||
property bool modalDarkenBackground: true
|
||||
|
||||
property bool lockScreenShowPowerActions: true
|
||||
property bool enableFprint: false
|
||||
property int maxFprintTries: 3
|
||||
property bool fprintdAvailable: false
|
||||
property bool hideBrightnessSlider: false
|
||||
|
||||
property int notificationTimeoutLow: 5000
|
||||
property int notificationTimeoutNormal: 5000
|
||||
property int notificationTimeoutCritical: 0
|
||||
property int notificationPopupPosition: SettingsData.Position.Top
|
||||
|
||||
property bool osdAlwaysShowValue: false
|
||||
|
||||
property bool powerActionConfirm: true
|
||||
property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]
|
||||
property string powerMenuDefaultAction: "logout"
|
||||
property string customPowerActionLock: ""
|
||||
property string customPowerActionLogout: ""
|
||||
property string customPowerActionSuspend: ""
|
||||
property string customPowerActionHibernate: ""
|
||||
property string customPowerActionReboot: ""
|
||||
property string customPowerActionPowerOff: ""
|
||||
|
||||
property bool updaterUseCustomCommand: false
|
||||
property string updaterCustomCommand: ""
|
||||
property string updaterTerminalAdditionalParams: ""
|
||||
|
||||
property var screenPreferences: ({})
|
||||
property var showOnLastDisplay: ({})
|
||||
|
||||
signal forceDankBarLayoutRefresh
|
||||
signal forceDockLayoutRefresh
|
||||
signal widgetDataChanged
|
||||
signal workspaceIconsUpdated
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
Processes.settingsRoot = root
|
||||
loadSettings()
|
||||
initializeListModels()
|
||||
Processes.detectFprintd()
|
||||
Processes.checkPluginSettings()
|
||||
}
|
||||
}
|
||||
|
||||
function applyStoredTheme() {
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.switchTheme(currentThemeName, false, false)
|
||||
} else {
|
||||
Qt.callLater(function() {
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.switchTheme(currentThemeName, false, false)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function regenSystemThemes() {
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function updateNiriLayout() {
|
||||
if (typeof NiriService !== "undefined" && typeof CompositorService !== "undefined" && CompositorService.isNiri) {
|
||||
NiriService.generateNiriLayoutConfig()
|
||||
}
|
||||
}
|
||||
|
||||
function applyStoredIconTheme() {
|
||||
updateGtkIconTheme()
|
||||
updateQtIconTheme()
|
||||
}
|
||||
|
||||
function updateGtkIconTheme() {
|
||||
const gtkThemeName = (iconTheme === "System Default") ? systemDefaultIconTheme : iconTheme
|
||||
if (gtkThemeName === "System Default" || gtkThemeName === "") return
|
||||
|
||||
if (typeof DMSService !== "undefined" && DMSService.apiVersion >= 3 && typeof PortalService !== "undefined") {
|
||||
PortalService.setSystemIconTheme(gtkThemeName)
|
||||
}
|
||||
|
||||
const configScript = `mkdir -p ${_configDir}/gtk-3.0 ${_configDir}/gtk-4.0
|
||||
|
||||
for config_dir in ${_configDir}/gtk-3.0 ${_configDir}/gtk-4.0; do
|
||||
settings_file="$config_dir/settings.ini"
|
||||
if [ -f "$settings_file" ]; then
|
||||
if grep -q "^gtk-icon-theme-name=" "$settings_file"; then
|
||||
sed -i 's/^gtk-icon-theme-name=.*/gtk-icon-theme-name=${gtkThemeName}/' "$settings_file"
|
||||
else
|
||||
if grep -q "\\[Settings\\]" "$settings_file"; then
|
||||
sed -i '/\\[Settings\\]/a gtk-icon-theme-name=${gtkThemeName}' "$settings_file"
|
||||
else
|
||||
echo -e '\\n[Settings]\\ngtk-icon-theme-name=${gtkThemeName}' >> "$settings_file"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e '[Settings]\\ngtk-icon-theme-name=${gtkThemeName}' > "$settings_file"
|
||||
fi
|
||||
done
|
||||
|
||||
rm -rf ~/.cache/icon-cache ~/.cache/thumbnails 2>/dev/null || true
|
||||
pkill -HUP -f 'gtk' 2>/dev/null || true`
|
||||
|
||||
Quickshell.execDetached(["sh", "-lc", configScript])
|
||||
}
|
||||
|
||||
function updateQtIconTheme() {
|
||||
const qtThemeName = (iconTheme === "System Default") ? "" : iconTheme
|
||||
if (!qtThemeName) return
|
||||
|
||||
const home = _homeUrl.replace("file://", "").replace(/'/g, "'\\''")
|
||||
const qtThemeNameEscaped = qtThemeName.replace(/'/g, "'\\''")
|
||||
|
||||
const script = `mkdir -p ${_configDir}/qt5ct ${_configDir}/qt6ct ${_configDir}/environment.d 2>/dev/null || true
|
||||
update_qt_icon_theme() {
|
||||
local config_file="$1"
|
||||
local theme_name="$2"
|
||||
if [ -f "$config_file" ]; then
|
||||
if grep -q "^\\[Appearance\\]" "$config_file"; then
|
||||
if grep -q "^icon_theme=" "$config_file"; then
|
||||
sed -i "s/^icon_theme=.*/icon_theme=$theme_name/" "$config_file"
|
||||
else
|
||||
sed -i "/^\\[Appearance\\]/a icon_theme=$theme_name" "$config_file"
|
||||
fi
|
||||
else
|
||||
printf "\\n[Appearance]\\nicon_theme=%s\\n" "$theme_name" >> "$config_file"
|
||||
fi
|
||||
else
|
||||
printf "[Appearance]\\nicon_theme=%s\\n" "$theme_name" > "$config_file"
|
||||
fi
|
||||
}
|
||||
update_qt_icon_theme ${_configDir}/qt5ct/qt5ct.conf '${qtThemeNameEscaped}'
|
||||
update_qt_icon_theme ${_configDir}/qt6ct/qt6ct.conf '${qtThemeNameEscaped}'
|
||||
rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || true`
|
||||
|
||||
Quickshell.execDetached(["sh", "-lc", script])
|
||||
}
|
||||
|
||||
readonly property var _hooks: ({
|
||||
applyStoredTheme: applyStoredTheme,
|
||||
regenSystemThemes: regenSystemThemes,
|
||||
updateNiriLayout: updateNiriLayout,
|
||||
applyStoredIconTheme: applyStoredIconTheme
|
||||
})
|
||||
|
||||
function set(key, value) {
|
||||
Spec.set(root, key, value, saveSettings, _hooks)
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
_loading = true
|
||||
try {
|
||||
const txt = settingsFile.text()
|
||||
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null
|
||||
Store.parse(root, obj)
|
||||
const shouldMigrate = Store.migrate(root, obj)
|
||||
applyStoredTheme()
|
||||
applyStoredIconTheme()
|
||||
Processes.detectIcons()
|
||||
Processes.detectQtTools()
|
||||
if (obj && obj.configVersion === undefined) {
|
||||
const cleaned = Store.cleanup(txt)
|
||||
if (cleaned) {
|
||||
settingsFile.setText(cleaned)
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
if (shouldMigrate) {
|
||||
savePluginSettings()
|
||||
saveSettings()
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SettingsData: Failed to load settings:", e.message)
|
||||
applyStoredTheme()
|
||||
applyStoredIconTheme()
|
||||
} finally {
|
||||
_loading = false
|
||||
}
|
||||
loadPluginSettings()
|
||||
}
|
||||
|
||||
function loadPluginSettings() {
|
||||
_pluginSettingsLoading = true
|
||||
parsePluginSettings(pluginSettingsFile.text())
|
||||
_pluginSettingsLoading = false
|
||||
}
|
||||
|
||||
function parsePluginSettings(content) {
|
||||
_pluginSettingsLoading = true
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
pluginSettings = JSON.parse(content)
|
||||
} else {
|
||||
pluginSettings = {}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SettingsData: Failed to parse plugin settings:", e.message)
|
||||
pluginSettings = {}
|
||||
} finally {
|
||||
_pluginSettingsLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
if (_loading) return
|
||||
settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2))
|
||||
}
|
||||
|
||||
function savePluginSettings() {
|
||||
if (_pluginSettingsLoading) return
|
||||
pluginSettingsFile.setText(JSON.stringify(pluginSettings, null, 2))
|
||||
}
|
||||
|
||||
function detectAvailableIconThemes() {
|
||||
Processes.detectIcons()
|
||||
}
|
||||
|
||||
function getEffectiveTimeFormat() {
|
||||
if (use24HourClock) {
|
||||
return showSeconds ? "hh:mm:ss" : "hh:mm"
|
||||
} else {
|
||||
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() {
|
||||
Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, dankBarLeftWidgets, dankBarCenterWidgets, dankBarRightWidgets)
|
||||
}
|
||||
|
||||
function updateListModel(listModel, order) {
|
||||
Lists.update(listModel, order)
|
||||
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 gothOffset = dankBarGothCornersEnabled ? Theme.cornerRadius : 0
|
||||
return barHeight + dankBarSpacing + dankBarBottomGap - gothOffset + Theme.popupDistance
|
||||
}
|
||||
|
||||
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth) {
|
||||
const screenX = screen ? screen.x : 0
|
||||
const screenY = screen ? screen.y : 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
const relativeY = globalPos.y - screenY
|
||||
|
||||
if (dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right) {
|
||||
return {
|
||||
"x": relativeY,
|
||||
"y": barThickness + dankBarSpacing + Theme.popupDistance,
|
||||
"width": widgetWidth
|
||||
}
|
||||
}
|
||||
return {
|
||||
"x": relativeX,
|
||||
"y": barThickness + dankBarSpacing + Theme.popupDistance,
|
||||
"width": widgetWidth
|
||||
}
|
||||
}
|
||||
|
||||
function getFilteredScreens(componentId) {
|
||||
var prefs = screenPreferences && screenPreferences[componentId] || ["all"]
|
||||
if (prefs.includes("all")) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
var filtered = Quickshell.screens.filter(screen => prefs.includes(screen.name))
|
||||
if (filtered.length === 0 && showOnLastDisplay && showOnLastDisplay[componentId] && Quickshell.screens.length === 1) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
function sendTestNotifications() {
|
||||
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) return
|
||||
set("matugenScheme", normalized)
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setRunUserMatugenTemplates(enabled) {
|
||||
if (runUserMatugenTemplates === enabled) return
|
||||
set("runUserMatugenTemplates", enabled)
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setMatugenTargetMonitor(monitorName) {
|
||||
if (matugenTargetMonitor === monitorName) return
|
||||
set("matugenTargetMonitor", monitorName)
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setCornerRadius(radius) {
|
||||
set("cornerRadius", radius)
|
||||
NiriService.generateNiriLayoutConfig()
|
||||
}
|
||||
|
||||
function setWeatherLocation(displayName, coordinates) {
|
||||
weatherLocation = displayName
|
||||
weatherCoordinates = coordinates
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setIconTheme(themeName) {
|
||||
iconTheme = themeName
|
||||
updateGtkIconTheme()
|
||||
updateQtIconTheme()
|
||||
saveSettings()
|
||||
if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic) Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
|
||||
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
|
||||
if (enabled && dockPosition === dankBarPosition) {
|
||||
if (dankBarPosition === SettingsData.Position.Top) {
|
||||
setDockPosition(SettingsData.Position.Bottom)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Bottom) {
|
||||
setDockPosition(SettingsData.Position.Top)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Left) {
|
||||
setDockPosition(SettingsData.Position.Right)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Right) {
|
||||
setDockPosition(SettingsData.Position.Left)
|
||||
return
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDockPosition(position) {
|
||||
dockPosition = position
|
||||
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Top)
|
||||
}
|
||||
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Bottom)
|
||||
}
|
||||
if (position === SettingsData.Position.Left && dankBarPosition === SettingsData.Position.Left && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Right)
|
||||
}
|
||||
if (position === SettingsData.Position.Right && dankBarPosition === SettingsData.Position.Right && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Left)
|
||||
}
|
||||
saveSettings()
|
||||
Qt.callLater(() => forceDockLayoutRefresh())
|
||||
}
|
||||
|
||||
function setDankBarSpacing(spacing) {
|
||||
set("dankBarSpacing", spacing)
|
||||
if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
|
||||
NiriService.generateNiriLayoutConfig()
|
||||
}
|
||||
}
|
||||
|
||||
function setDankBarPosition(position) {
|
||||
dankBarPosition = position
|
||||
if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) {
|
||||
setDockPosition(SettingsData.Position.Top)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Top && dockPosition === SettingsData.Position.Top && showDock) {
|
||||
setDockPosition(SettingsData.Position.Bottom)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Left && dockPosition === SettingsData.Position.Left && showDock) {
|
||||
setDockPosition(SettingsData.Position.Right)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Right && dockPosition === SettingsData.Position.Right && showDock) {
|
||||
setDockPosition(SettingsData.Position.Left)
|
||||
return
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarLeftWidgets(order) {
|
||||
dankBarLeftWidgets = order
|
||||
updateListModel(leftWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarCenterWidgets(order) {
|
||||
dankBarCenterWidgets = order
|
||||
updateListModel(centerWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarRightWidgets(order) {
|
||||
dankBarRightWidgets = order
|
||||
updateListModel(rightWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function resetDankBarWidgetsToDefault() {
|
||||
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
var defaultCenter = ["music", "clock", "weather"]
|
||||
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]
|
||||
dankBarLeftWidgets = defaultLeft
|
||||
dankBarCenterWidgets = defaultCenter
|
||||
dankBarRightWidgets = 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
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWorkspaceNameIcon(workspaceName, iconData) {
|
||||
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons))
|
||||
iconMap[workspaceName] = iconData
|
||||
workspaceNameIcons = iconMap
|
||||
saveSettings()
|
||||
workspaceIconsUpdated()
|
||||
}
|
||||
|
||||
function removeWorkspaceNameIcon(workspaceName) {
|
||||
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons))
|
||||
delete iconMap[workspaceName]
|
||||
workspaceNameIcons = iconMap
|
||||
saveSettings()
|
||||
workspaceIconsUpdated()
|
||||
}
|
||||
|
||||
function getWorkspaceNameIcon(workspaceName) {
|
||||
return workspaceNameIcons[workspaceName] || null
|
||||
}
|
||||
|
||||
function toggleDankBarVisible() {
|
||||
dankBarVisible = !dankBarVisible
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getPluginSetting(pluginId, key, defaultValue) {
|
||||
if (!pluginSettings[pluginId]) {
|
||||
return defaultValue
|
||||
}
|
||||
return pluginSettings[pluginId][key] !== undefined ? pluginSettings[pluginId][key] : defaultValue
|
||||
}
|
||||
|
||||
function setPluginSetting(pluginId, key, value) {
|
||||
const updated = JSON.parse(JSON.stringify(pluginSettings))
|
||||
if (!updated[pluginId]) {
|
||||
updated[pluginId] = {}
|
||||
}
|
||||
updated[pluginId][key] = value
|
||||
pluginSettings = updated
|
||||
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)) : {}
|
||||
}
|
||||
|
||||
|
||||
ListModel {
|
||||
id: leftWidgetsModel
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: centerWidgetsModel
|
||||
}
|
||||
|
||||
ListModel {
|
||||
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
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
try {
|
||||
const txt = settingsFile.text()
|
||||
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null
|
||||
Store.parse(root, obj)
|
||||
Store.migrate(root, obj)
|
||||
} catch (e) {
|
||||
console.warn("SettingsData: Failed to reload settings:", e.message)
|
||||
}
|
||||
hasTriedDefaultSettings = false
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
||||
hasTriedDefaultSettings = true
|
||||
Processes.checkDefaultSettings()
|
||||
} else if (!isGreeterMode) {
|
||||
applyStoredTheme()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: pluginSettingsFile
|
||||
|
||||
path: isGreeterMode ? "" : pluginSettingsPath
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parsePluginSettings(pluginSettingsFile.text())
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode) {
|
||||
pluginSettings = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property bool pluginSettingsFileExists: false
|
||||
|
||||
IpcHandler {
|
||||
function reveal(): string {
|
||||
root.setDankBarVisible(true)
|
||||
return "BAR_SHOW_SUCCESS"
|
||||
}
|
||||
|
||||
function hide(): string {
|
||||
root.setDankBarVisible(false)
|
||||
return "BAR_HIDE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
root.toggleDankBarVisible()
|
||||
return root.dankBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
return root.dankBarVisible ? "visible" : "hidden"
|
||||
}
|
||||
|
||||
target: "bar"
|
||||
}
|
||||
}
|
||||
545
quickshell/Common/StockThemes.js
Normal file
545
quickshell/Common/StockThemes.js
Normal file
@@ -0,0 +1,545 @@
|
||||
// Stock theme definitions for DankMaterialShell
|
||||
// Separated from Theme.qml to keep that file clean
|
||||
|
||||
const CatppuccinMocha = {
|
||||
surface: "#313244",
|
||||
surfaceText: "#cdd6f4",
|
||||
surfaceVariant: "#313244",
|
||||
surfaceVariantText: "#a6adc8",
|
||||
background: "#1e1e2e",
|
||||
backgroundText: "#cdd6f4",
|
||||
outline: "#6c7086",
|
||||
surfaceContainer: "#45475a",
|
||||
surfaceContainerHigh: "#585b70",
|
||||
surfaceContainerHighest: "#6c7086"
|
||||
}
|
||||
|
||||
const CatppuccinLatte = {
|
||||
surface: "#e6e9ef",
|
||||
surfaceText: "#4c4f69",
|
||||
surfaceVariant: "#e6e9ef",
|
||||
surfaceVariantText: "#6c6f85",
|
||||
background: "#eff1f5",
|
||||
backgroundText: "#4c4f69",
|
||||
outline: "#9ca0b0",
|
||||
surfaceContainer: "#dce0e8",
|
||||
surfaceContainerHigh: "#ccd0da",
|
||||
surfaceContainerHighest: "#bcc0cc"
|
||||
}
|
||||
|
||||
const CatppuccinVariants = {
|
||||
"cat-rosewater": {
|
||||
name: "Rosewater",
|
||||
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#7d5d56", surfaceTint: "#f5e0dc" },
|
||||
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f6e7e3", surfaceTint: "#dc8a78" }
|
||||
},
|
||||
"cat-flamingo": {
|
||||
name: "Flamingo",
|
||||
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#7a555a", surfaceTint: "#f2cdcd" },
|
||||
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f6e5e5", surfaceTint: "#dd7878" }
|
||||
},
|
||||
"cat-pink": {
|
||||
name: "Pink",
|
||||
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#7a3f69", surfaceTint: "#f5c2e7" },
|
||||
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7d7ee", surfaceTint: "#ea76cb" }
|
||||
},
|
||||
"cat-mauve": {
|
||||
name: "Mauve",
|
||||
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#55307f", surfaceTint: "#cba6f7" },
|
||||
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#eadcff", surfaceTint: "#8839ef" }
|
||||
},
|
||||
"cat-red": {
|
||||
name: "Red",
|
||||
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#6f2438", surfaceTint: "#f38ba8" },
|
||||
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f6d0d6", surfaceTint: "#d20f39" }
|
||||
},
|
||||
"cat-maroon": {
|
||||
name: "Maroon",
|
||||
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#6d3641", surfaceTint: "#eba0ac" },
|
||||
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f7d8dc", surfaceTint: "#e64553" }
|
||||
},
|
||||
"cat-peach": {
|
||||
name: "Peach",
|
||||
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#734226", surfaceTint: "#fab387" },
|
||||
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffe4d5", surfaceTint: "#fe640b" }
|
||||
},
|
||||
"cat-yellow": {
|
||||
name: "Yellow",
|
||||
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#6e5a2f", surfaceTint: "#f9e2af" },
|
||||
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff6d6", surfaceTint: "#df8e1d" }
|
||||
},
|
||||
"cat-green": {
|
||||
name: "Green",
|
||||
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#2f5f36", surfaceTint: "#a6e3a1" },
|
||||
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#dff4e0", surfaceTint: "#40a02b" }
|
||||
},
|
||||
"cat-teal": {
|
||||
name: "Teal",
|
||||
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2e5e59", surfaceTint: "#94e2d5" },
|
||||
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#daf3f1", surfaceTint: "#179299" }
|
||||
},
|
||||
"cat-sky": {
|
||||
name: "Sky",
|
||||
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#24586a", surfaceTint: "#89dceb" },
|
||||
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#dbf1fb", surfaceTint: "#04a5e5" }
|
||||
},
|
||||
"cat-sapphire": {
|
||||
name: "Sapphire",
|
||||
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#1f4d6f", surfaceTint: "#74c7ec" },
|
||||
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#def3f8", surfaceTint: "#209fb5" }
|
||||
},
|
||||
"cat-blue": {
|
||||
name: "Blue",
|
||||
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#243f75", surfaceTint: "#89b4fa" },
|
||||
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e0e9ff", surfaceTint: "#1e66f5" }
|
||||
},
|
||||
"cat-lavender": {
|
||||
name: "Lavender",
|
||||
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#3f4481", surfaceTint: "#b4befe" },
|
||||
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#e5e8ff", surfaceTint: "#7287fd" }
|
||||
}
|
||||
}
|
||||
|
||||
function getCatppuccinTheme(variant, isLight = false) {
|
||||
const variantData = CatppuccinVariants[variant]
|
||||
if (!variantData) return null
|
||||
|
||||
const baseColors = isLight ? CatppuccinLatte : CatppuccinMocha
|
||||
const accentColors = isLight ? variantData.light : variantData.dark
|
||||
|
||||
return Object.assign({
|
||||
name: `${variantData.name}${isLight ? ' Light' : ''}`
|
||||
}, baseColors, accentColors)
|
||||
}
|
||||
|
||||
const StockThemes = {
|
||||
DARK: {
|
||||
blue: {
|
||||
name: "Blue",
|
||||
primary: "#42a5f5",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#0d47a1",
|
||||
secondary: "#8ab4f8",
|
||||
surface: "#101418",
|
||||
surfaceText: "#e0e2e8",
|
||||
surfaceVariant: "#42474e",
|
||||
surfaceVariantText: "#c2c7cf",
|
||||
surfaceTint: "#8ab4f8",
|
||||
background: "#101418",
|
||||
backgroundText: "#e0e2e8",
|
||||
outline: "#8c9199",
|
||||
surfaceContainer: "#1d2024",
|
||||
surfaceContainerHigh: "#272a2f",
|
||||
surfaceContainerHighest: "#32353a"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple",
|
||||
primary: "#D0BCFF",
|
||||
primaryText: "#381E72",
|
||||
primaryContainer: "#4F378B",
|
||||
secondary: "#CCC2DC",
|
||||
surface: "#141218",
|
||||
surfaceText: "#e6e0e9",
|
||||
surfaceVariant: "#49454e",
|
||||
surfaceVariantText: "#cac4cf",
|
||||
surfaceTint: "#D0BCFF",
|
||||
background: "#141218",
|
||||
backgroundText: "#e6e0e9",
|
||||
outline: "#948f99",
|
||||
surfaceContainer: "#211f24",
|
||||
surfaceContainerHigh: "#2b292f",
|
||||
surfaceContainerHighest: "#36343a"
|
||||
},
|
||||
green: {
|
||||
name: "Green",
|
||||
primary: "#4caf50",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#1b5e20",
|
||||
secondary: "#81c995",
|
||||
surface: "#10140f",
|
||||
surfaceText: "#e0e4db",
|
||||
surfaceVariant: "#424940",
|
||||
surfaceVariantText: "#c2c9bd",
|
||||
surfaceTint: "#81c995",
|
||||
background: "#10140f",
|
||||
backgroundText: "#e0e4db",
|
||||
outline: "#8c9388",
|
||||
surfaceContainer: "#1d211b",
|
||||
surfaceContainerHigh: "#272b25",
|
||||
surfaceContainerHighest: "#323630"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange",
|
||||
primary: "#ff6d00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#3e2723",
|
||||
secondary: "#ffb74d",
|
||||
surface: "#1a120e",
|
||||
surfaceText: "#f0dfd8",
|
||||
surfaceVariant: "#52443d",
|
||||
surfaceVariantText: "#d7c2b9",
|
||||
surfaceTint: "#ffb74d",
|
||||
background: "#1a120e",
|
||||
backgroundText: "#f0dfd8",
|
||||
outline: "#a08d85",
|
||||
surfaceContainer: "#271e1a",
|
||||
surfaceContainerHigh: "#322824",
|
||||
surfaceContainerHighest: "#3d332e"
|
||||
},
|
||||
red: {
|
||||
name: "Red",
|
||||
primary: "#f44336",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e0e",
|
||||
secondary: "#f28b82",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2be",
|
||||
surfaceTint: "#f28b82",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c89",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
primary: "#00bcd4",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#004d5c",
|
||||
secondary: "#4dd0e1",
|
||||
surface: "#0e1416",
|
||||
surfaceText: "#dee3e5",
|
||||
surfaceVariant: "#3f484a",
|
||||
surfaceVariantText: "#bfc8ca",
|
||||
surfaceTint: "#4dd0e1",
|
||||
background: "#0e1416",
|
||||
backgroundText: "#dee3e5",
|
||||
outline: "#899295",
|
||||
surfaceContainer: "#1b2122",
|
||||
surfaceContainerHigh: "#252b2c",
|
||||
surfaceContainerHighest: "#303637"
|
||||
},
|
||||
pink: {
|
||||
name: "Pink",
|
||||
primary: "#e91e63",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e2f",
|
||||
secondary: "#f8bbd9",
|
||||
surface: "#191112",
|
||||
surfaceText: "#f0dee0",
|
||||
surfaceVariant: "#524345",
|
||||
surfaceVariantText: "#d6c2c3",
|
||||
surfaceTint: "#f8bbd9",
|
||||
background: "#191112",
|
||||
backgroundText: "#f0dee0",
|
||||
outline: "#9f8c8e",
|
||||
surfaceContainer: "#261d1e",
|
||||
surfaceContainerHigh: "#312829",
|
||||
surfaceContainerHighest: "#3c3233"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber",
|
||||
primary: "#ffc107",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a3c00",
|
||||
secondary: "#ffd54f",
|
||||
surface: "#17130b",
|
||||
surfaceText: "#ebe1d4",
|
||||
surfaceVariant: "#4d4639",
|
||||
surfaceVariantText: "#d0c5b4",
|
||||
surfaceTint: "#ffd54f",
|
||||
background: "#17130b",
|
||||
backgroundText: "#ebe1d4",
|
||||
outline: "#998f80",
|
||||
surfaceContainer: "#231f17",
|
||||
surfaceContainerHigh: "#2e2921",
|
||||
surfaceContainerHighest: "#39342b"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral",
|
||||
primary: "#ffb4ab",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#8c1d18",
|
||||
secondary: "#f9dedc",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2bf",
|
||||
surfaceTint: "#ffb4ab",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c8a",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome",
|
||||
primary: "#ffffff",
|
||||
primaryText: "#2b303c",
|
||||
primaryContainer: "#424753",
|
||||
secondary: "#c4c6d0",
|
||||
surface: "#2a2a2a",
|
||||
surfaceText: "#e4e2e3",
|
||||
surfaceVariant: "#474648",
|
||||
surfaceVariantText: "#c8c6c7",
|
||||
surfaceTint: "#c2c6d6",
|
||||
background: "#131315",
|
||||
backgroundText: "#e4e2e3",
|
||||
outline: "#929092",
|
||||
surfaceContainer: "#353535",
|
||||
surfaceContainerHigh: "#424242",
|
||||
surfaceContainerHighest: "#505050",
|
||||
error: "#ffb4ab",
|
||||
warning: "#3f4759",
|
||||
info: "#595e6c",
|
||||
matugen_type: "scheme-monochrome"
|
||||
}
|
||||
},
|
||||
LIGHT: {
|
||||
blue: {
|
||||
name: "Blue Light",
|
||||
primary: "#1976d2",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e3f2fd",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#f7f9ff",
|
||||
surfaceText: "#181c20",
|
||||
surfaceVariant: "#dee3eb",
|
||||
surfaceVariantText: "#42474e",
|
||||
surfaceTint: "#1976d2",
|
||||
background: "#f7f9ff",
|
||||
backgroundText: "#181c20",
|
||||
outline: "#72777f",
|
||||
surfaceContainer: "#eceef4",
|
||||
surfaceContainerHigh: "#e6e8ee",
|
||||
surfaceContainerHighest: "#e0e2e8"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple Light",
|
||||
primary: "#6750A4",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#EADDFF",
|
||||
secondary: "#625B71",
|
||||
surface: "#fef7ff",
|
||||
surfaceText: "#1d1b20",
|
||||
surfaceVariant: "#e7e0eb",
|
||||
surfaceVariantText: "#49454e",
|
||||
surfaceTint: "#6750A4",
|
||||
background: "#fef7ff",
|
||||
backgroundText: "#1d1b20",
|
||||
outline: "#7a757f",
|
||||
surfaceContainer: "#f2ecf4",
|
||||
surfaceContainerHigh: "#ece6ee",
|
||||
surfaceContainerHighest: "#e6e0e9"
|
||||
},
|
||||
green: {
|
||||
name: "Green Light",
|
||||
primary: "#2e7d32",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e8f5e8",
|
||||
secondary: "#4caf50",
|
||||
surface: "#f7fbf1",
|
||||
surfaceText: "#191d17",
|
||||
surfaceVariant: "#dee5d8",
|
||||
surfaceVariantText: "#424940",
|
||||
surfaceTint: "#2e7d32",
|
||||
background: "#f7fbf1",
|
||||
backgroundText: "#191d17",
|
||||
outline: "#72796f",
|
||||
surfaceContainer: "#ecefe6",
|
||||
surfaceContainerHigh: "#e6e9e0",
|
||||
surfaceContainerHighest: "#e0e4db"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange Light",
|
||||
primary: "#e65100",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffecb3",
|
||||
secondary: "#ff9800",
|
||||
surface: "#fff8f6",
|
||||
surfaceText: "#221a16",
|
||||
surfaceVariant: "#f4ded5",
|
||||
surfaceVariantText: "#52443d",
|
||||
surfaceTint: "#e65100",
|
||||
background: "#fff8f6",
|
||||
backgroundText: "#221a16",
|
||||
outline: "#85736c",
|
||||
surfaceContainer: "#fceae3",
|
||||
surfaceContainerHigh: "#f6e5de",
|
||||
surfaceContainerHighest: "#f0dfd8"
|
||||
},
|
||||
red: {
|
||||
name: "Red Light",
|
||||
primary: "#d32f2f",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffebee",
|
||||
secondary: "#f44336",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#d32f2f",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857370",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f7e4e1",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan Light",
|
||||
primary: "#0097a7",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e0f2f1",
|
||||
secondary: "#00bcd4",
|
||||
surface: "#f5fafc",
|
||||
surfaceText: "#171d1e",
|
||||
surfaceVariant: "#dbe4e6",
|
||||
surfaceVariantText: "#3f484a",
|
||||
surfaceTint: "#0097a7",
|
||||
background: "#f5fafc",
|
||||
backgroundText: "#171d1e",
|
||||
outline: "#6f797b",
|
||||
surfaceContainer: "#e9eff0",
|
||||
surfaceContainerHigh: "#e3e9eb",
|
||||
surfaceContainerHighest: "#dee3e5"
|
||||
},
|
||||
pink: {
|
||||
name: "Pink Light",
|
||||
primary: "#c2185b",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#fce4ec",
|
||||
secondary: "#e91e63",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#22191a",
|
||||
surfaceVariant: "#f3dddf",
|
||||
surfaceVariantText: "#524345",
|
||||
surfaceTint: "#c2185b",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#22191a",
|
||||
outline: "#847375",
|
||||
surfaceContainer: "#fbeaeb",
|
||||
surfaceContainerHigh: "#f5e4e5",
|
||||
surfaceContainerHighest: "#f0dee0"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber Light",
|
||||
primary: "#ff8f00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#fff8e1",
|
||||
secondary: "#ffc107",
|
||||
surface: "#fff8f2",
|
||||
surfaceText: "#1f1b13",
|
||||
surfaceVariant: "#ede1cf",
|
||||
surfaceVariantText: "#4d4639",
|
||||
surfaceTint: "#ff8f00",
|
||||
background: "#fff8f2",
|
||||
backgroundText: "#1f1b13",
|
||||
outline: "#7f7667",
|
||||
surfaceContainer: "#f6ecdf",
|
||||
surfaceContainerHigh: "#f1e7d9",
|
||||
surfaceContainerHighest: "#ebe1d4"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral Light",
|
||||
primary: "#8c1d18",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffdad6",
|
||||
secondary: "#ff5449",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#8c1d18",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857371",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f6e4e2",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome Light",
|
||||
primary: "#2b303c",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#d6d7dc",
|
||||
secondary: "#4a4d56",
|
||||
surface: "#f5f5f6",
|
||||
surfaceText: "#2a2a2a",
|
||||
surfaceVariant: "#e0e0e2",
|
||||
surfaceVariantText: "#424242",
|
||||
surfaceTint: "#5a5f6e",
|
||||
background: "#ffffff",
|
||||
backgroundText: "#1a1a1a",
|
||||
outline: "#757577",
|
||||
surfaceContainer: "#e8e8ea",
|
||||
surfaceContainerHigh: "#dcdcde",
|
||||
surfaceContainerHighest: "#d0d0d2",
|
||||
error: "#ba1a1a",
|
||||
warning: "#f9e79f",
|
||||
info: "#5d6475",
|
||||
matugen_type: "scheme-monochrome"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ThemeCategories = {
|
||||
GENERIC: {
|
||||
name: "Generic",
|
||||
variants: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
},
|
||||
CATPPUCCIN: {
|
||||
name: "Catppuccin",
|
||||
variants: Object.keys(CatppuccinVariants)
|
||||
}
|
||||
}
|
||||
|
||||
const ThemeNames = {
|
||||
BLUE: "blue",
|
||||
PURPLE: "purple",
|
||||
GREEN: "green",
|
||||
ORANGE: "orange",
|
||||
RED: "red",
|
||||
CYAN: "cyan",
|
||||
PINK: "pink",
|
||||
AMBER: "amber",
|
||||
CORAL: "coral",
|
||||
MONOCHROME: "monochrome",
|
||||
DYNAMIC: "dynamic"
|
||||
}
|
||||
|
||||
function isStockTheme(themeName) {
|
||||
return Object.keys(StockThemes.DARK).includes(themeName)
|
||||
}
|
||||
|
||||
function isCatppuccinVariant(themeName) {
|
||||
return Object.keys(CatppuccinVariants).includes(themeName)
|
||||
}
|
||||
|
||||
function getAvailableThemes(isLight = false) {
|
||||
return isLight ? StockThemes.LIGHT : StockThemes.DARK
|
||||
}
|
||||
|
||||
function getThemeByName(themeName, isLight = false) {
|
||||
if (isCatppuccinVariant(themeName)) {
|
||||
return getCatppuccinTheme(themeName, isLight)
|
||||
}
|
||||
const themes = getAvailableThemes(isLight)
|
||||
return themes[themeName] || themes.blue
|
||||
}
|
||||
|
||||
function getAllThemeNames() {
|
||||
return Object.keys(StockThemes.DARK)
|
||||
}
|
||||
|
||||
function getCatppuccinVariantNames() {
|
||||
return Object.keys(CatppuccinVariants)
|
||||
}
|
||||
|
||||
function getThemeCategories() {
|
||||
return ThemeCategories
|
||||
}
|
||||
1130
quickshell/Common/Theme.qml
Normal file
1130
quickshell/Common/Theme.qml
Normal file
File diff suppressed because it is too large
Load Diff
1307
quickshell/Common/fzf.js
Normal file
1307
quickshell/Common/fzf.js
Normal file
File diff suppressed because it is too large
Load Diff
106
quickshell/Common/markdown2html.js
Normal file
106
quickshell/Common/markdown2html.js
Normal file
@@ -0,0 +1,106 @@
|
||||
.pragma library
|
||||
// This exists only beacause I haven't been able to get linkColor to work with MarkdownText
|
||||
// May not be necessary if that's possible tbh.
|
||||
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, '>');
|
||||
codeBlocks.push(`<pre><code>${escapedCode}</code></pre>`);
|
||||
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, '>');
|
||||
inlineCode.push(`<code>${escapedCode}</code>`);
|
||||
return `\x00INLINECODE${inlineIndex++}\x00`;
|
||||
});
|
||||
|
||||
// Now process everything else
|
||||
// Escape HTML entities (but not in code blocks)
|
||||
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>');
|
||||
|
||||
// Bold and italic (order matters!)
|
||||
html = html.replace(/\*\*\*(.*?)\*\*\*/g, '<b><i>$1</i></b>');
|
||||
html = html.replace(/\*\*(.*?)\*\*/g, '<b>$1</b>');
|
||||
html = html.replace(/\*(.*?)\*/g, '<i>$1</i>');
|
||||
html = html.replace(/___(.*?)___/g, '<b><i>$1</i></b>');
|
||||
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>';
|
||||
});
|
||||
|
||||
// Detect plain URLs and wrap them in anchor tags (but not inside existing <a> or markdown links)
|
||||
html = html.replace(/(^|[^"'>])((https?|file):\/\/[^\s<]+)/g, '$1<a href="$2">$2</a>');
|
||||
|
||||
// Restore code blocks and inline code BEFORE line break processing
|
||||
html = html.replace(/\x00CODEBLOCK(\d+)\x00/g, (match, index) => {
|
||||
return codeBlocks[parseInt(index)];
|
||||
});
|
||||
|
||||
html = html.replace(/\x00INLINECODE(\d+)\x00/g, (match, index) => {
|
||||
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
|
||||
|
||||
// Remove leading/trailing whitespace
|
||||
html = html.trim();
|
||||
|
||||
return html;
|
||||
}
|
||||
56
quickshell/Common/settings/Lists.qml
Normal file
56
quickshell/Common/settings/Lists.qml
Normal file
@@ -0,0 +1,56 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
function init(leftModel, centerModel, rightModel, left, center, right) {
|
||||
const dummy = {
|
||||
widgetId: "dummy",
|
||||
enabled: true,
|
||||
size: 20,
|
||||
selectedGpuIndex: 0,
|
||||
pciId: "",
|
||||
mountPath: "/",
|
||||
minimumWidth: true,
|
||||
showSwap: false
|
||||
}
|
||||
leftModel.append(dummy)
|
||||
centerModel.append(dummy)
|
||||
rightModel.append(dummy)
|
||||
|
||||
update(leftModel, left)
|
||||
update(centerModel, center)
|
||||
update(rightModel, right)
|
||||
}
|
||||
|
||||
function update(model, order) {
|
||||
model.clear()
|
||||
for (var i = 0; i < order.length; i++) {
|
||||
var widgetId = typeof order[i] === "string" ? order[i] : order[i].id
|
||||
var enabled = typeof order[i] === "string" ? true : order[i].enabled
|
||||
var size = typeof order[i] === "string" ? undefined : order[i].size
|
||||
var selectedGpuIndex = typeof order[i] === "string" ? undefined : order[i].selectedGpuIndex
|
||||
var pciId = typeof order[i] === "string" ? undefined : order[i].pciId
|
||||
var mountPath = typeof order[i] === "string" ? undefined : order[i].mountPath
|
||||
var minimumWidth = typeof order[i] === "string" ? undefined : order[i].minimumWidth
|
||||
var showSwap = typeof order[i] === "string" ? undefined : order[i].showSwap
|
||||
var item = {
|
||||
widgetId: widgetId,
|
||||
enabled: enabled
|
||||
}
|
||||
if (size !== undefined) item.size = size
|
||||
if (selectedGpuIndex !== undefined) item.selectedGpuIndex = selectedGpuIndex
|
||||
if (pciId !== undefined) item.pciId = pciId
|
||||
if (mountPath !== undefined) item.mountPath = mountPath
|
||||
if (minimumWidth !== undefined) item.minimumWidth = minimumWidth
|
||||
if (showSwap !== undefined) item.showSwap = showSwap
|
||||
|
||||
model.append(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
131
quickshell/Common/settings/Processes.qml
Normal file
131
quickshell/Common/settings/Processes.qml
Normal file
@@ -0,0 +1,131 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var settingsRoot: null
|
||||
|
||||
function detectIcons() {
|
||||
systemDefaultDetectionProcess.running = true
|
||||
}
|
||||
|
||||
function detectQtTools() {
|
||||
qtToolsDetectionProcess.running = true
|
||||
}
|
||||
|
||||
function detectFprintd() {
|
||||
fprintdDetectionProcess.running = true
|
||||
}
|
||||
|
||||
function checkPluginSettings() {
|
||||
pluginSettingsCheckProcess.running = true
|
||||
}
|
||||
|
||||
function checkDefaultSettings() {
|
||||
defaultSettingsCheckProcess.running = true
|
||||
}
|
||||
|
||||
property var systemDefaultDetectionProcess: Process {
|
||||
command: ["sh", "-c", "gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed \"s/'//g\" || echo ''"]
|
||||
running: false
|
||||
onExited: function(exitCode) {
|
||||
if (!settingsRoot) return;
|
||||
if (exitCode === 0 && stdout && stdout.length > 0) {
|
||||
settingsRoot.systemDefaultIconTheme = stdout.trim();
|
||||
} else {
|
||||
settingsRoot.systemDefaultIconTheme = "";
|
||||
}
|
||||
iconThemeDetectionProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
property var iconThemeDetectionProcess: Process {
|
||||
|
||||
command: ["sh", "-c", "find /usr/share/icons ~/.local/share/icons ~/.icons -maxdepth 1 -type d 2>/dev/null | sed 's|.*/||' | grep -v '^icons$' | sort -u"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (!settingsRoot) return
|
||||
var detectedThemes = ["System Default"]
|
||||
if (text && text.trim()) {
|
||||
var themes = text.trim().split('\n')
|
||||
for (var i = 0; i < themes.length; i++) {
|
||||
var theme = themes[i].trim()
|
||||
if (theme && theme !== "" && theme !== "default" && theme !== "hicolor" && theme !== "locolor") {
|
||||
detectedThemes.push(theme)
|
||||
}
|
||||
}
|
||||
}
|
||||
settingsRoot.availableIconThemes = detectedThemes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var qtToolsDetectionProcess: Process {
|
||||
command: ["sh", "-c", "echo -n 'qt5ct:'; command -v qt5ct >/dev/null && echo 'true' || echo 'false'; echo -n 'qt6ct:'; command -v qt6ct >/dev/null && echo 'true' || echo 'false'; echo -n 'gtk:'; (command -v gsettings >/dev/null || command -v dconf >/dev/null) && echo 'true' || echo 'false'"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (!settingsRoot) return;
|
||||
if (text && text.trim()) {
|
||||
var lines = text.trim().split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
if (line.startsWith('qt5ct:')) {
|
||||
settingsRoot.qt5ctAvailable = line.split(':')[1] === 'true';
|
||||
} else if (line.startsWith('qt6ct:')) {
|
||||
settingsRoot.qt6ctAvailable = line.split(':')[1] === 'true';
|
||||
} else if (line.startsWith('gtk:')) {
|
||||
settingsRoot.gtkAvailable = line.split(':')[1] === 'true';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var defaultSettingsCheckProcess: Process {
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + (settingsRoot?._configDir || "") + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
running: false
|
||||
onExited: function(exitCode) {
|
||||
if (!settingsRoot) return;
|
||||
if (exitCode === 0) {
|
||||
console.info("Copied default-settings.json to settings.json");
|
||||
if (settingsRoot.settingsFile) {
|
||||
settingsRoot.settingsFile.reload();
|
||||
}
|
||||
} else {
|
||||
if (typeof ThemeApplier !== "undefined") {
|
||||
ThemeApplier.applyStoredTheme(settingsRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var fprintdDetectionProcess: Process {
|
||||
command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"]
|
||||
running: false
|
||||
onExited: function(exitCode) {
|
||||
if (!settingsRoot) return;
|
||||
settingsRoot.fprintdAvailable = (exitCode === 0);
|
||||
}
|
||||
}
|
||||
|
||||
property var pluginSettingsCheckProcess: Process {
|
||||
command: ["test", "-f", settingsRoot?.pluginSettingsPath || ""]
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (!settingsRoot) return;
|
||||
settingsRoot.pluginSettingsFileExists = (exitCode === 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
235
quickshell/Common/settings/SettingsSpec.js
Normal file
235
quickshell/Common/settings/SettingsSpec.js
Normal file
@@ -0,0 +1,235 @@
|
||||
.pragma library
|
||||
|
||||
function percentToUnit(v) {
|
||||
if (v === undefined || v === null) return undefined;
|
||||
return v > 1 ? v / 100 : v;
|
||||
}
|
||||
|
||||
var SPEC = {
|
||||
currentThemeName: { def: "blue", onChange: "applyStoredTheme" },
|
||||
customThemeFile: { def: "" },
|
||||
matugenScheme: { def: "scheme-tonal-spot", onChange: "regenSystemThemes" },
|
||||
runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" },
|
||||
matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" },
|
||||
|
||||
dankBarTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarTransparency"] },
|
||||
dankBarWidgetTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarWidgetTransparency"] },
|
||||
popupTransparency: { def: 1.0, coerce: percentToUnit },
|
||||
dockTransparency: { def: 1.0, coerce: percentToUnit },
|
||||
|
||||
widgetBackgroundColor: { def: "sch" },
|
||||
cornerRadius: { def: 12, onChange: "updateNiriLayout" },
|
||||
|
||||
use24HourClock: { def: true },
|
||||
showSeconds: { def: false },
|
||||
useFahrenheit: { def: false },
|
||||
nightModeEnabled: { def: false },
|
||||
animationSpeed: { def: 1 },
|
||||
customAnimationDuration: { def: 500 },
|
||||
wallpaperFillMode: { def: "Fill" },
|
||||
blurredWallpaperLayer: { def: false },
|
||||
blurWallpaperOnOverview: { def: false },
|
||||
|
||||
showLauncherButton: { def: true },
|
||||
showWorkspaceSwitcher: { def: true },
|
||||
showFocusedWindow: { def: true },
|
||||
showWeather: { def: true },
|
||||
showMusic: { def: true },
|
||||
showClipboard: { def: true },
|
||||
showCpuUsage: { def: true },
|
||||
showMemUsage: { def: true },
|
||||
showCpuTemp: { def: true },
|
||||
showGpuTemp: { def: true },
|
||||
selectedGpuIndex: { def: 0 },
|
||||
enabledGpuPciIds: { def: [] },
|
||||
showSystemTray: { def: true },
|
||||
showClock: { def: true },
|
||||
showNotificationButton: { def: true },
|
||||
showBattery: { def: true },
|
||||
showControlCenterButton: { def: true },
|
||||
|
||||
controlCenterShowNetworkIcon: { def: true },
|
||||
controlCenterShowBluetoothIcon: { def: true },
|
||||
controlCenterShowAudioIcon: { def: true },
|
||||
controlCenterWidgets: { def: [
|
||||
{ id: "volumeSlider", enabled: true, width: 50 },
|
||||
{ id: "brightnessSlider", enabled: true, width: 50 },
|
||||
{ id: "wifi", enabled: true, width: 50 },
|
||||
{ id: "bluetooth", enabled: true, width: 50 },
|
||||
{ id: "audioOutput", enabled: true, width: 50 },
|
||||
{ id: "audioInput", enabled: true, width: 50 },
|
||||
{ id: "nightMode", enabled: true, width: 50 },
|
||||
{ id: "darkMode", enabled: true, width: 50 }
|
||||
]},
|
||||
|
||||
showWorkspaceIndex: { def: false },
|
||||
showWorkspacePadding: { def: false },
|
||||
workspaceScrolling: { def: false },
|
||||
showWorkspaceApps: { def: false },
|
||||
maxWorkspaceIcons: { def: 3 },
|
||||
workspacesPerMonitor: { def: true },
|
||||
dwlShowAllTags: { def: false },
|
||||
workspaceNameIcons: { def: {} },
|
||||
waveProgressEnabled: { def: true },
|
||||
clockCompactMode: { def: false },
|
||||
focusedWindowCompactMode: { def: false },
|
||||
runningAppsCompactMode: { def: true },
|
||||
keyboardLayoutNameCompactMode: { def: false },
|
||||
runningAppsCurrentWorkspace: { def: false },
|
||||
runningAppsGroupByApp: { def: false },
|
||||
clockDateFormat: { def: "" },
|
||||
lockDateFormat: { def: "" },
|
||||
mediaSize: { def: 1 },
|
||||
|
||||
dankBarLeftWidgets: { def: ["launcherButton", "workspaceSwitcher", "focusedWindow"], migrate: ["topBarLeftWidgets"] },
|
||||
dankBarCenterWidgets: { def: ["music", "clock", "weather"], migrate: ["topBarCenterWidgets"] },
|
||||
dankBarRightWidgets: { def: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], migrate: ["topBarRightWidgets"] },
|
||||
dankBarWidgetOrder: { def: [] },
|
||||
|
||||
appLauncherViewMode: { def: "list" },
|
||||
spotlightModalViewMode: { def: "list" },
|
||||
sortAppsAlphabetically: { def: false },
|
||||
|
||||
weatherLocation: { def: "New York, NY" },
|
||||
weatherCoordinates: { def: "40.7128,-74.0060" },
|
||||
useAutoLocation: { def: false },
|
||||
weatherEnabled: { def: true },
|
||||
|
||||
networkPreference: { def: "auto" },
|
||||
vpnLastConnected: { def: "" },
|
||||
|
||||
iconTheme: { def: "System Default", onChange: "applyStoredIconTheme" },
|
||||
availableIconThemes: { def: ["System Default"], persist: false },
|
||||
systemDefaultIconTheme: { def: "", persist: false },
|
||||
qt5ctAvailable: { def: false, persist: false },
|
||||
qt6ctAvailable: { def: false, persist: false },
|
||||
gtkAvailable: { def: false, persist: false },
|
||||
|
||||
launcherLogoMode: { def: "apps" },
|
||||
launcherLogoCustomPath: { def: "" },
|
||||
launcherLogoColorOverride: { def: "" },
|
||||
launcherLogoColorInvertOnMode: { def: false },
|
||||
launcherLogoBrightness: { def: 0.5 },
|
||||
launcherLogoContrast: { def: 1 },
|
||||
launcherLogoSizeOffset: { def: 0 },
|
||||
|
||||
fontFamily: { def: "Inter Variable" },
|
||||
monoFontFamily: { def: "Fira Code" },
|
||||
fontWeight: { def: 400 },
|
||||
fontScale: { def: 1.0 },
|
||||
dankBarFontScale: { def: 1.0 },
|
||||
|
||||
notepadUseMonospace: { def: true },
|
||||
notepadFontFamily: { def: "" },
|
||||
notepadFontSize: { def: 14 },
|
||||
notepadShowLineNumbers: { def: false },
|
||||
notepadTransparencyOverride: { def: -1 },
|
||||
notepadLastCustomTransparency: { def: 0.7 },
|
||||
|
||||
soundsEnabled: { def: true },
|
||||
useSystemSoundTheme: { def: false },
|
||||
soundNewNotification: { def: true },
|
||||
soundVolumeChanged: { def: true },
|
||||
soundPluggedIn: { def: true },
|
||||
|
||||
acMonitorTimeout: { def: 0 },
|
||||
acLockTimeout: { def: 0 },
|
||||
acSuspendTimeout: { def: 0 },
|
||||
acSuspendBehavior: { def: 0 },
|
||||
batteryMonitorTimeout: { def: 0 },
|
||||
batteryLockTimeout: { def: 0 },
|
||||
batterySuspendTimeout: { def: 0 },
|
||||
batterySuspendBehavior: { def: 0 },
|
||||
lockBeforeSuspend: { def: false },
|
||||
preventIdleForMedia: { def: false },
|
||||
loginctlLockIntegration: { def: true },
|
||||
launchPrefix: { def: "" },
|
||||
brightnessDevicePins: { def: {} },
|
||||
|
||||
gtkThemingEnabled: { def: false, onChange: "regenSystemThemes" },
|
||||
qtThemingEnabled: { def: false, onChange: "regenSystemThemes" },
|
||||
syncModeWithPortal: { def: true },
|
||||
|
||||
showDock: { def: false },
|
||||
dockAutoHide: { def: false },
|
||||
dockGroupByApp: { def: false },
|
||||
dockOpenOnOverview: { def: false },
|
||||
dockPosition: { def: 1 },
|
||||
dockSpacing: { def: 4 },
|
||||
dockBottomGap: { def: 0 },
|
||||
dockMargin: { def: 0 },
|
||||
dockIconSize: { def: 40 },
|
||||
dockIndicatorStyle: { def: "circle" },
|
||||
|
||||
notificationOverlayEnabled: { def: false },
|
||||
dankBarAutoHide: { def: false, migrate: ["topBarAutoHide"] },
|
||||
dankBarOpenOnOverview: { def: false, migrate: ["topBarOpenOnOverview"] },
|
||||
dankBarVisible: { def: true, migrate: ["topBarVisible"] },
|
||||
overviewRows: { def: 2, persist: false },
|
||||
overviewColumns: { def: 5, persist: false },
|
||||
overviewScale: { def: 0.16, persist: false },
|
||||
dankBarSpacing: { def: 4, migrate: ["topBarSpacing"], onChange: "updateNiriLayout" },
|
||||
dankBarBottomGap: { def: 0, migrate: ["topBarBottomGap"] },
|
||||
dankBarInnerPadding: { def: 4, migrate: ["topBarInnerPadding"] },
|
||||
dankBarPosition: { def: 0, migrate: ["dankBarAtBottom", "topBarAtBottom"] },
|
||||
dankBarIsVertical: { def: false, persist: false },
|
||||
|
||||
dankBarSquareCorners: { def: false, migrate: ["topBarSquareCorners"] },
|
||||
dankBarNoBackground: { def: false, migrate: ["topBarNoBackground"] },
|
||||
dankBarGothCornersEnabled: { def: false, migrate: ["topBarGothCornersEnabled"] },
|
||||
dankBarGothCornerRadiusOverride: { def: false },
|
||||
dankBarGothCornerRadiusValue: { def: 12 },
|
||||
dankBarBorderEnabled: { def: false },
|
||||
dankBarBorderColor: { def: "surfaceText" },
|
||||
dankBarBorderOpacity: { def: 1.0 },
|
||||
dankBarBorderThickness: { def: 1 },
|
||||
|
||||
popupGapsAuto: { def: true },
|
||||
popupGapsManual: { def: 4 },
|
||||
|
||||
modalDarkenBackground: { def: true },
|
||||
|
||||
lockScreenShowPowerActions: { def: true },
|
||||
enableFprint: { def: false },
|
||||
maxFprintTries: { def: 3 },
|
||||
fprintdAvailable: { def: false, persist: false },
|
||||
hideBrightnessSlider: { def: false },
|
||||
|
||||
notificationTimeoutLow: { def: 5000 },
|
||||
notificationTimeoutNormal: { def: 5000 },
|
||||
notificationTimeoutCritical: { def: 0 },
|
||||
notificationPopupPosition: { def: 0 },
|
||||
|
||||
osdAlwaysShowValue: { def: false },
|
||||
|
||||
powerActionConfirm: { def: true },
|
||||
powerMenuActions: { def: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] },
|
||||
powerMenuDefaultAction: { def: "logout" },
|
||||
customPowerActionLock: { def: "" },
|
||||
customPowerActionLogout: { def: "" },
|
||||
customPowerActionSuspend: { def: "" },
|
||||
customPowerActionHibernate: { def: "" },
|
||||
customPowerActionReboot: { def: "" },
|
||||
customPowerActionPowerOff: { def: "" },
|
||||
|
||||
updaterUseCustomCommand: { def: false },
|
||||
updaterCustomCommand: { def: "" },
|
||||
updaterTerminalAdditionalParams: { def: "" },
|
||||
|
||||
screenPreferences: { def: {} },
|
||||
showOnLastDisplay: { def: {} }
|
||||
};
|
||||
|
||||
function getValidKeys() {
|
||||
return Object.keys(SPEC).filter(function(k) { return SPEC[k].persist !== false; }).concat(["configVersion"]);
|
||||
}
|
||||
|
||||
function set(root, key, value, saveFn, hooks) {
|
||||
if (!(key in SPEC)) return;
|
||||
root[key] = value;
|
||||
var hookName = SPEC[key].onChange;
|
||||
if (hookName && hooks && hooks[hookName]) {
|
||||
hooks[hookName](root);
|
||||
}
|
||||
saveFn();
|
||||
}
|
||||
118
quickshell/Common/settings/SettingsStore.js
Normal file
118
quickshell/Common/settings/SettingsStore.js
Normal file
@@ -0,0 +1,118 @@
|
||||
.pragma library
|
||||
|
||||
.import "./SettingsSpec.js" as SpecModule
|
||||
|
||||
function parse(root, jsonObj) {
|
||||
var SPEC = SpecModule.SPEC;
|
||||
for (var k in SPEC) {
|
||||
var spec = SPEC[k];
|
||||
root[k] = spec.def;
|
||||
}
|
||||
|
||||
if (!jsonObj) return;
|
||||
|
||||
for (var k in jsonObj) {
|
||||
if (!SPEC[k]) continue;
|
||||
var raw = jsonObj[k];
|
||||
var spec = SPEC[k];
|
||||
var coerce = spec.coerce;
|
||||
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
|
||||
}
|
||||
}
|
||||
|
||||
function toJson(root) {
|
||||
var SPEC = SpecModule.SPEC;
|
||||
var out = {};
|
||||
for (var k in SPEC) {
|
||||
if (SPEC[k].persist === false) continue;
|
||||
out[k] = root[k];
|
||||
}
|
||||
out.configVersion = root.settingsConfigVersion;
|
||||
return out;
|
||||
}
|
||||
|
||||
function migrate(root, jsonObj) {
|
||||
var SPEC = SpecModule.SPEC;
|
||||
if (!jsonObj) return;
|
||||
|
||||
if (jsonObj.themeIndex !== undefined || jsonObj.themeIsDynamic !== undefined) {
|
||||
var themeNames = ["blue", "deepBlue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral"];
|
||||
if (jsonObj.themeIsDynamic) {
|
||||
root.currentThemeName = "dynamic";
|
||||
} else if (jsonObj.themeIndex >= 0 && jsonObj.themeIndex < themeNames.length) {
|
||||
root.currentThemeName = themeNames[jsonObj.themeIndex];
|
||||
}
|
||||
console.info("Auto-migrated theme from index", jsonObj.themeIndex, "to", root.currentThemeName);
|
||||
}
|
||||
|
||||
if ((jsonObj.dankBarWidgetOrder && jsonObj.dankBarWidgetOrder.length > 0) ||
|
||||
(jsonObj.topBarWidgetOrder && jsonObj.topBarWidgetOrder.length > 0)) {
|
||||
if (jsonObj.dankBarLeftWidgets === undefined && jsonObj.dankBarCenterWidgets === undefined && jsonObj.dankBarRightWidgets === undefined) {
|
||||
var widgetOrder = jsonObj.dankBarWidgetOrder || jsonObj.topBarWidgetOrder;
|
||||
root.dankBarLeftWidgets = widgetOrder.filter(function(w) { return ["launcherButton", "workspaceSwitcher", "focusedWindow"].indexOf(w) >= 0; });
|
||||
root.dankBarCenterWidgets = widgetOrder.filter(function(w) { return ["clock", "music", "weather"].indexOf(w) >= 0; });
|
||||
root.dankBarRightWidgets = widgetOrder.filter(function(w) { return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].indexOf(w) >= 0; });
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObj.useOSLogo !== undefined) {
|
||||
root.launcherLogoMode = jsonObj.useOSLogo ? "os" : "apps";
|
||||
root.launcherLogoColorOverride = jsonObj.osLogoColorOverride !== undefined ? jsonObj.osLogoColorOverride : "";
|
||||
root.launcherLogoBrightness = jsonObj.osLogoBrightness !== undefined ? jsonObj.osLogoBrightness : 0.5;
|
||||
root.launcherLogoContrast = jsonObj.osLogoContrast !== undefined ? jsonObj.osLogoContrast : 1;
|
||||
}
|
||||
|
||||
if (jsonObj.mediaCompactMode !== undefined && jsonObj.mediaSize === undefined) {
|
||||
root.mediaSize = jsonObj.mediaCompactMode ? 0 : 1;
|
||||
}
|
||||
|
||||
for (var k in SPEC) {
|
||||
var spec = SPEC[k];
|
||||
if (!spec.migrate) continue;
|
||||
for (var i = 0; i < spec.migrate.length; i++) {
|
||||
var oldKey = spec.migrate[i];
|
||||
if (jsonObj[oldKey] !== undefined && jsonObj[k] === undefined) {
|
||||
var raw = jsonObj[oldKey];
|
||||
var coerce = spec.coerce;
|
||||
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObj.dankBarAtBottom !== undefined || jsonObj.topBarAtBottom !== undefined) {
|
||||
var atBottom = jsonObj.dankBarAtBottom !== undefined ? jsonObj.dankBarAtBottom : jsonObj.topBarAtBottom;
|
||||
root.dankBarPosition = atBottom ? 1 : 0;
|
||||
}
|
||||
|
||||
if (jsonObj.pluginSettings !== undefined) {
|
||||
root.pluginSettings = jsonObj.pluginSettings;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
console.log("SettingsData: Removing unused key:", key);
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user