Merge branch 'github-main'

This commit is contained in:
Never Gude 2025-09-08 13:32:06 +02:00
commit 6e009d3551
72 changed files with 2510 additions and 1137 deletions

View file

@ -102,7 +102,7 @@ Singleton {
// FileView to load custom colors data from colors.json
FileView {
id: customColorsFile
path: Settings.configDir + "colors.json"
path: Settings.directoriesCreated ? (Settings.configDir + "colors.json") : ""
watchChanges: true
onFileChanged: {
Logger.log("Color", "Reloading colors from disk")
@ -112,6 +112,13 @@ Singleton {
Logger.log("Color", "Writing colors to disk")
writeAdapter()
}
// Trigger initial load when path changes from empty to actual path
onPathChanged: {
if (path === Settings.configDir + "colors.json") {
reload()
}
}
onLoadFailed: function (error) {
if (error.toString().includes("No such file") || error === 2) {
// File doesn't exist, create it with default values

View file

@ -26,11 +26,13 @@ Singleton {
property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers"
property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos"
property string defaultLocation: "Tokyo"
property string defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"
// Used to access via Settings.data.xxx.yyy
readonly property alias data: adapter
property bool isLoaded: false
property bool directoriesCreated: false
// Signal emitted when settings are loaded after startupcale changes
signal settingsLoaded
@ -71,34 +73,93 @@ Singleton {
// -----------------------------------------------------
// If the settings structure has changed, ensure
// backward compatibility
// backward compatibility by upgrading the settings
function upgradeSettingsData() {
for (var i = 0; i < adapter.bar.widgets.left.length; i++) {
var obj = adapter.bar.widgets.left[i]
if (typeof obj === "string") {
adapter.bar.widgets.left[i] = {
"id": obj
const sections = ["left", "center", "right"]
// -----------------
// 1st. check our settings are not super old, when we only had the widget type as a plain string
for (var s = 0; s < sections.length; s++) {
const sectionName = sections[s]
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
var widget = adapter.bar.widgets[sectionName][i]
if (typeof widget === "string") {
adapter.bar.widgets[sectionName][i] = {
"id": widget
}
}
}
}
for (var i = 0; i < adapter.bar.widgets.center.length; i++) {
var obj = adapter.bar.widgets.center[i]
if (typeof obj === "string") {
adapter.bar.widgets.center[i] = {
"id": obj
// -----------------
// 2nd. migrate global settings to user settings
for (var s = 0; s < sections.length; s++) {
const sectionName = sections[s]
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
var widget = adapter.bar.widgets[sectionName][i]
// Check if widget registry supports user settings, if it does not, then there is nothing to do
const reg = BarWidgetRegistry.widgetMetadata[widget.id]
if ((reg === undefined) || (reg.allowUserSettings === undefined) || !reg.allowUserSettings) {
continue
}
}
}
for (var i = 0; i < adapter.bar.widgets.right.length; i++) {
var obj = adapter.bar.widgets.right[i]
if (typeof obj === "string") {
adapter.bar.widgets.right[i] = {
"id": obj
// Check that the widget was not previously migrated and skip if necessary
const keys = Object.keys(widget)
if (keys.length > 1) {
continue
}
migrateWidget(widget)
Logger.log("Settings", JSON.stringify(widget))
}
}
}
// -----------------------------------------------------
function migrateWidget(widget) {
Logger.log("Settings", `Migrating '${widget.id}' widget`)
switch (widget.id) {
case "ActiveWindow":
widget.showIcon = adapter.bar.showActiveWindowIcon
break
case "Battery":
widget.alwaysShowPercentage = adapter.bar.alwaysShowBatteryPercentage
break
case "Brightness":
widget.alwaysShowPercentage = BarWidgetRegistry.widgetMetadata[widget.id].alwaysShowPercentage
break
case "Clock":
widget.showDate = adapter.location.showDateWithClock
widget.use12HourClock = adapter.location.use12HourClock
widget.reverseDayMonth = adapter.location.reverseDayMonth
widget.showSeconds = BarWidgetRegistry.widgetMetadata[widget.id].showSeconds
break
case "MediaMini":
widget.showAlbumArt = adapter.audio.showMiniplayerAlbumArt
widget.showVisualizer = adapter.audio.showMiniplayerCava
widget.visualizerType = BarWidgetRegistry.widgetMetadata[widget.id].visualizerType
break
case "NotificationHistory":
widget.showUnreadBadge = BarWidgetRegistry.widgetMetadata[widget.id].showUnreadBadge
widget.hideWhenZero = BarWidgetRegistry.widgetMetadata[widget.id].hideWhenZero
break
case "SidePanelToggle":
widget.useDistroLogo = adapter.bar.useDistroLogo
break
case "SystemMonitor":
widget.showNetworkStats = adapter.bar.showNetworkStats
break
case "Volume":
widget.alwaysShowPercentage = BarWidgetRegistry.widgetMetadata[widget.id].alwaysShowPercentage
break
case "Workspace":
widget.labelMode = adapter.bar.showWorkspaceLabel
break
}
}
// -----------------------------------------------------
// Kickoff essential services
function kickOffServices() {
@ -117,14 +178,15 @@ Singleton {
}
// -----------------------------------------------------
Item {
Component.onCompleted: {
// Ensure directories exist before FileView tries to read files
Component.onCompleted: {
// ensure settings dir exists
Quickshell.execDetached(["mkdir", "-p", configDir])
Quickshell.execDetached(["mkdir", "-p", cacheDir])
Quickshell.execDetached(["mkdir", "-p", cacheDirImages])
// ensure settings dir exists
Quickshell.execDetached(["mkdir", "-p", configDir])
Quickshell.execDetached(["mkdir", "-p", cacheDir])
Quickshell.execDetached(["mkdir", "-p", cacheDirImages])
}
// Mark directories as created and trigger file loading
directoriesCreated = true
}
// Don't write settings to disk immediately
@ -138,12 +200,16 @@ Singleton {
FileView {
id: settingsFileView
path: settingsFile
path: directoriesCreated ? settingsFile : ""
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: saveTimer.start()
Component.onCompleted: function () {
reload()
// Trigger initial load when path changes from empty to actual path
onPathChanged: {
if (path === settingsFile) {
reload()
}
}
onLoaded: function () {
if (!isLoaded) {
@ -174,15 +240,16 @@ Singleton {
// bar
property JsonObject bar: JsonObject {
property string position: "top" // Possible values: "top", "bottom"
property bool showActiveWindowIcon: true
property bool alwaysShowBatteryPercentage: false
property bool showNetworkStats: false
property string position: "top" // "top" or "bottom"
property real backgroundOpacity: 1.0
property bool useDistroLogo: false
property string showWorkspaceLabel: "none"
property list<string> monitors: []
property bool showActiveWindowIcon: true // TODO: delete
property bool alwaysShowBatteryPercentage: false // TODO: delete
property bool showNetworkStats: false // TODO: delete
property bool useDistroLogo: false // TODO: delete
property string showWorkspaceLabel: "none" // TODO: delete
// Widget configuration for modular bar system
property JsonObject widgets
widgets: JsonObject {
@ -236,9 +303,10 @@ Singleton {
property JsonObject location: JsonObject {
property string name: defaultLocation
property bool useFahrenheit: false
property bool reverseDayMonth: false
property bool use12HourClock: false
property bool showDateWithClock: false
property bool reverseDayMonth: false // TODO: delete
property bool use12HourClock: false // TODO: delete
property bool showDateWithClock: false // TODO: delete
}
// screen recorder
@ -267,6 +335,7 @@ Singleton {
property int transitionDuration: 1500 // 1500 ms
property string transitionType: "random"
property real transitionEdgeSmoothness: 0.05
property string defaultWallpaper: root.defaultWallpaper
property list<var> monitors: []
}
@ -299,25 +368,27 @@ Singleton {
property JsonObject notifications: JsonObject {
property bool doNotDisturb: false
property list<string> monitors: []
// Last time the user opened the notification history (ms since epoch)
property real lastSeenTs: 0
}
// audio
property JsonObject audio: JsonObject {
property bool showMiniplayerAlbumArt: false
property bool showMiniplayerCava: false
property string visualizerType: "linear"
property int volumeStep: 5
property int cavaFrameRate: 60
// MPRIS controls
property string visualizerType: "linear"
property list<string> mprisBlacklist: []
property string preferredPlayer: ""
property bool showMiniplayerAlbumArt: false // TODO: delete
property bool showMiniplayerCava: false // TODO: delete
}
// ui
property JsonObject ui: JsonObject {
property string fontDefault: "Roboto" // Default font for all text
property string fontFixed: "DejaVu Sans Mono" // Fixed width font for terminal
property string fontBillboard: "Inter" // Large bold font for clocks and prominent displays
property string fontDefault: "Roboto"
property string fontFixed: "DejaVu Sans Mono"
property string fontBillboard: "Inter"
property list<var> monitorsScaling: []
property bool idleInhibitorEnabled: false
}

View file

@ -60,6 +60,7 @@ Singleton {
property int animationFast: Math.round(150 * Settings.data.general.animationSpeed)
property int animationNormal: Math.round(300 * Settings.data.general.animationSpeed)
property int animationSlow: Math.round(450 * Settings.data.general.animationSpeed)
property int animationSlowest: Math.round(750 * Settings.data.general.animationSpeed)
// Dimensions
property int barHeight: 36

View file

@ -9,52 +9,38 @@ Singleton {
id: root
property var date: new Date()
property string time: {
let timeFormat = Settings.data.location.use12HourClock ? "h:mm AP" : "HH:mm"
let timeString = Qt.formatDateTime(date, timeFormat)
if (Settings.data.location.showDateWithClock) {
let dayName = date.toLocaleDateString(Qt.locale(), "ddd")
dayName = dayName.charAt(0).toUpperCase() + dayName.slice(1)
let day = date.getDate()
let month = date.toLocaleDateString(Qt.locale(), "MMM")
return timeString + " - " + (Settings.data.location.reverseDayMonth ? `${dayName}, ${month} ${day}` : `${dayName}, ${day} ${month}`)
}
return timeString
// Returns a Unix Timestamp (in seconds)
readonly property int timestamp: {
return Math.floor(date / 1000)
}
readonly property string dateString: {
function formatDate(reverseDayMonth = true) {
let now = date
let dayName = now.toLocaleDateString(Qt.locale(), "ddd")
dayName = dayName.charAt(0).toUpperCase() + dayName.slice(1)
let day = now.getDate()
let suffix
if (day > 3 && day < 21)
suffix = 'th'
suffix = 'th'
else
switch (day % 10) {
switch (day % 10) {
case 1:
suffix = "st"
break
suffix = "st"
break
case 2:
suffix = "nd"
break
suffix = "nd"
break
case 3:
suffix = "rd"
break
suffix = "rd"
break
default:
suffix = "th"
}
suffix = "th"
}
let month = now.toLocaleDateString(Qt.locale(), "MMMM")
let year = now.toLocaleDateString(Qt.locale(), "yyyy")
return `${dayName}, `
+ (Settings.data.location.reverseDayMonth ? `${month} ${day}${suffix} ${year}` : `${day}${suffix} ${month} ${year}`)
}
// Returns a Unix Timestamp (in seconds)
readonly property int timestamp: {
return Math.floor(date / 1000)
return `${dayName}, ` + (reverseDayMonth ? `${month} ${day}${suffix} ${year}` : `${day}${suffix} ${month} ${year}`)
}