configoptions: use quickshell jsonadapter

This commit is contained in:
end-4
2025-06-30 14:27:26 +02:00
parent 22319ffccf
commit 7ca0f263ba
50 changed files with 455 additions and 546 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ Singleton {
Timer { Timer {
id: workspaceShowNumbersTimer id: workspaceShowNumbersTimer
interval: ConfigOptions.bar.workspaces.showNumberDelay interval: Config.options.bar.workspaces.showNumberDelay
// interval: 0 // interval: 0
repeat: false repeat: false
onTriggered: { onTriggered: {
@@ -15,12 +15,12 @@ import Quickshell.Services.UPower
Scope { Scope {
id: root id: root
property string filePath: `${Directories.state}/user/generated/wallpaper/least_busy_region.json` property string filePath: `${Directories.state}/user/generated/wallpaper/least_busy_region.json`
property real defaultX: (ConfigOptions?.background.clockX ?? -500) property real defaultX: (Config.options?.background.clockX ?? -500)
property real defaultY: (ConfigOptions?.background.clockY ?? -500) property real defaultY: (Config.options?.background.clockY ?? -500)
property real centerX: defaultX property real centerX: defaultX
property real centerY: defaultY property real centerY: defaultY
property real effectiveCenterX: ConfigOptions?.background.fixedClockPosition ? defaultX : centerX property real effectiveCenterX: Config.options?.background.fixedClockPosition ? defaultX : centerX
property real effectiveCenterY: ConfigOptions?.background.fixedClockPosition ? defaultY : centerY property real effectiveCenterY: Config.options?.background.fixedClockPosition ? defaultY : centerY
property color dominantColor: Appearance.colors.colPrimary property color dominantColor: Appearance.colors.colPrimary
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5 property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
property color colBackground: ColorUtils.transparentize(ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer), 1) property color colBackground: ColorUtils.transparentize(ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer), 1)
@@ -36,7 +36,7 @@ Scope {
Timer { Timer {
id: delayedFileRead id: delayedFileRead
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay interval: Config.options.hacks.arbitraryRaceConditionDelay
running: false running: false
onTriggered: { onTriggered: {
root.updateWidgetPosition(leastBusyRegionFileView.text()) root.updateWidgetPosition(leastBusyRegionFileView.text())
@@ -46,7 +46,7 @@ Scope {
FileView { FileView {
id: leastBusyRegionFileView id: leastBusyRegionFileView
path: Qt.resolvedUrl(root.filePath) path: Qt.resolvedUrl(root.filePath)
watchChanges: !ConfigOptions?.background.fixedClockPosition watchChanges: !Config.options?.background.fixedClockPosition
onFileChanged: { onFileChanged: {
this.reload() this.reload()
delayedFileRead.start() delayedFileRead.start()
+21 -21
View File
@@ -16,7 +16,7 @@ Scope {
id: bar id: bar
readonly property int osdHideMouseMoveThreshold: 20 readonly property int osdHideMouseMoveThreshold: 20
property bool showBarBackground: ConfigOptions.bar.showBackground property bool showBarBackground: Config.options.bar.showBackground
component VerticalBarSeparator: Rectangle { component VerticalBarSeparator: Rectangle {
Layout.topMargin: Appearance.sizes.baseBarHeight / 3 Layout.topMargin: Appearance.sizes.baseBarHeight / 3
@@ -29,7 +29,7 @@ Scope {
Variants { // For each monitor Variants { // For each monitor
model: { model: {
const screens = Quickshell.screens; const screens = Quickshell.screens;
const list = ConfigOptions.bar.screenList; const list = Config.options.bar.screenList;
if (!list || list.length === 0) if (!list || list.length === 0)
return screens; return screens;
return screens.filter(screen => list.includes(screen.name)); return screens.filter(screen => list.includes(screen.name));
@@ -50,15 +50,15 @@ Scope {
WlrLayershell.namespace: "quickshell:bar" WlrLayershell.namespace: "quickshell:bar"
implicitHeight: Appearance.sizes.barHeight + Appearance.rounding.screenRounding implicitHeight: Appearance.sizes.barHeight + Appearance.rounding.screenRounding
exclusiveZone: Appearance.sizes.baseBarHeight + (ConfigOptions.bar.cornerStyle === 1 ? Appearance.sizes.hyprlandGapsOut : 0) exclusiveZone: Appearance.sizes.baseBarHeight + (Config.options.bar.cornerStyle === 1 ? Appearance.sizes.hyprlandGapsOut : 0)
mask: Region { mask: Region {
item: barContent item: barContent
} }
color: "transparent" color: "transparent"
anchors { anchors {
top: !ConfigOptions.bar.bottom top: !Config.options.bar.bottom
bottom: ConfigOptions.bar.bottom bottom: Config.options.bar.bottom
left: true left: true
right: true right: true
} }
@@ -76,7 +76,7 @@ Scope {
states: State { states: State {
name: "bottom" name: "bottom"
when: ConfigOptions.bar.bottom when: Config.options.bar.bottom
AnchorChanges { AnchorChanges {
target: barContent target: barContent
anchors { anchors {
@@ -90,7 +90,7 @@ Scope {
// Background shadow // Background shadow
Loader { Loader {
active: showBarBackground && ConfigOptions.bar.cornerStyle === 1 active: showBarBackground && Config.options.bar.cornerStyle === 1
anchors.fill: barBackground anchors.fill: barBackground
sourceComponent: StyledRectangularShadow { sourceComponent: StyledRectangularShadow {
anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor
@@ -102,10 +102,10 @@ Scope {
id: barBackground id: barBackground
anchors { anchors {
fill: parent fill: parent
margins: ConfigOptions.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed
} }
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent" color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
radius: ConfigOptions.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0 radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0
} }
MouseArea { // Left side | scroll to change brightness MouseArea { // Left side | scroll to change brightness
@@ -204,7 +204,7 @@ Scope {
anchors.centerIn: parent anchors.centerIn: parent
width: 19.5 width: 19.5
height: 19.5 height: 19.5
source: ConfigOptions.bar.topLeftIcon == 'distro' ? source: Config.options.bar.topLeftIcon == 'distro' ?
SystemInfo.distroIcon : "spark-symbolic" SystemInfo.distroIcon : "spark-symbolic"
} }
@@ -229,7 +229,7 @@ Scope {
RowLayout { // Middle section RowLayout { // Middle section
id: middleSection id: middleSection
anchors.centerIn: parent anchors.centerIn: parent
spacing: ConfigOptions?.bar.borderless ? 4 : 8 spacing: Config.options?.bar.borderless ? 4 : 8
BarGroup { BarGroup {
id: leftCenterGroup id: leftCenterGroup
@@ -248,7 +248,7 @@ Scope {
} }
VerticalBarSeparator {visible: ConfigOptions?.bar.borderless} VerticalBarSeparator {visible: Config.options?.bar.borderless}
BarGroup { BarGroup {
id: middleCenterGroup id: middleCenterGroup
@@ -272,7 +272,7 @@ Scope {
} }
} }
VerticalBarSeparator {visible: ConfigOptions?.bar.borderless} VerticalBarSeparator {visible: Config.options?.bar.borderless}
MouseArea { MouseArea {
id: rightCenterGroup id: rightCenterGroup
@@ -290,13 +290,13 @@ Scope {
anchors.fill: parent anchors.fill: parent
ClockWidget { ClockWidget {
showDate: (ConfigOptions.bar.verbose && barRoot.useShortenedForm < 2) showDate: (Config.options.bar.verbose && barRoot.useShortenedForm < 2)
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true Layout.fillWidth: true
} }
UtilButtons { UtilButtons {
visible: (ConfigOptions.bar.verbose && barRoot.useShortenedForm === 0) visible: (Config.options.bar.verbose && barRoot.useShortenedForm === 0)
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
} }
@@ -495,11 +495,11 @@ Scope {
y: Appearance.sizes.barHeight y: Appearance.sizes.barHeight
width: parent.width width: parent.width
height: Appearance.rounding.screenRounding height: Appearance.rounding.screenRounding
active: showBarBackground && ConfigOptions.bar.cornerStyle === 0 // Hug active: showBarBackground && Config.options.bar.cornerStyle === 0 // Hug
states: State { states: State {
name: "bottom" name: "bottom"
when: ConfigOptions.bar.bottom when: Config.options.bar.bottom
PropertyChanges { PropertyChanges {
roundDecorators.y: 0 roundDecorators.y: 0
} }
@@ -522,7 +522,7 @@ Scope {
corner: RoundCorner.CornerEnum.TopLeft corner: RoundCorner.CornerEnum.TopLeft
states: State { states: State {
name: "bottom" name: "bottom"
when: ConfigOptions.bar.bottom when: Config.options.bar.bottom
PropertyChanges { PropertyChanges {
leftCorner.corner: RoundCorner.CornerEnum.BottomLeft leftCorner.corner: RoundCorner.CornerEnum.BottomLeft
} }
@@ -532,8 +532,8 @@ Scope {
id: rightCorner id: rightCorner
anchors { anchors {
right: parent.right right: parent.right
top: !ConfigOptions.bar.bottom ? parent.top : undefined top: !Config.options.bar.bottom ? parent.top : undefined
bottom: ConfigOptions.bar.bottom ? parent.bottom : undefined bottom: Config.options.bar.bottom ? parent.bottom : undefined
} }
size: Appearance.rounding.screenRounding size: Appearance.rounding.screenRounding
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent" color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
@@ -542,7 +542,7 @@ Scope {
corner: RoundCorner.CornerEnum.TopRight corner: RoundCorner.CornerEnum.TopRight
states: State { states: State {
name: "bottom" name: "bottom"
when: ConfigOptions.bar.bottom when: Config.options.bar.bottom
PropertyChanges { PropertyChanges {
rightCorner.corner: RoundCorner.CornerEnum.BottomRight rightCorner.corner: RoundCorner.CornerEnum.BottomRight
} }
+1 -1
View File
@@ -19,7 +19,7 @@ Item {
topMargin: 4 topMargin: 4
bottomMargin: 4 bottomMargin: 4
} }
color: ConfigOptions?.bar.borderless ? "transparent" : Appearance.colors.colLayer1 color: Config.options?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
radius: Appearance.rounding.small radius: Appearance.rounding.small
} }
@@ -9,12 +9,12 @@ import Quickshell.Services.UPower
Item { Item {
id: root id: root
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
readonly property var chargeState: Battery.chargeState readonly property var chargeState: Battery.chargeState
readonly property bool isCharging: Battery.isCharging readonly property bool isCharging: Battery.isCharging
readonly property bool isPluggedIn: Battery.isPluggedIn readonly property bool isPluggedIn: Battery.isPluggedIn
readonly property real percentage: Battery.percentage readonly property real percentage: Battery.percentage
readonly property bool isLow: percentage <= ConfigOptions.battery.low / 100 readonly property bool isLow: percentage <= Config.options.battery.low / 100
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
@@ -6,8 +6,8 @@ import QtQuick.Layouts
Item { Item {
id: root id: root
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
property bool showDate: ConfigOptions.bar.verbose property bool showDate: Config.options.bar.verbose
implicitWidth: rowLayout.implicitWidth implicitWidth: rowLayout.implicitWidth
implicitHeight: 32 implicitHeight: 32
+1 -1
View File
@@ -11,7 +11,7 @@ import Quickshell.Hyprland
Item { Item {
id: root id: root
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
readonly property MprisPlayer activePlayer: MprisController.activePlayer readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || qsTr("No media") readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || qsTr("No media")
+3 -3
View File
@@ -9,7 +9,7 @@ import Quickshell.Services.Mpris
Item { Item {
id: root id: root
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
property bool alwaysShowAllResources: false property bool alwaysShowAllResources: false
implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
implicitHeight: 32 implicitHeight: 32
@@ -30,7 +30,7 @@ Item {
Resource { Resource {
iconName: "swap_horiz" iconName: "swap_horiz"
percentage: ResourceUsage.swapUsedPercentage percentage: ResourceUsage.swapUsedPercentage
shown: (ConfigOptions.bar.resources.alwaysShowSwap && percentage > 0) || shown: (Config.options.bar.resources.alwaysShowSwap && percentage > 0) ||
(MprisController.activePlayer?.trackTitle == null) || (MprisController.activePlayer?.trackTitle == null) ||
root.alwaysShowAllResources root.alwaysShowAllResources
Layout.leftMargin: shown ? 4 : 0 Layout.leftMargin: shown ? 4 : 0
@@ -39,7 +39,7 @@ Item {
Resource { Resource {
iconName: "settings_slow_motion" iconName: "settings_slow_motion"
percentage: ResourceUsage.cpuUsage percentage: ResourceUsage.cpuUsage
shown: ConfigOptions.bar.resources.alwaysShowCpu || shown: Config.options.bar.resources.alwaysShowCpu ||
!(MprisController.activePlayer?.trackTitle?.length > 0) || !(MprisController.activePlayer?.trackTitle?.length > 0) ||
root.alwaysShowAllResources root.alwaysShowAllResources
Layout.leftMargin: shown ? 4 : 0 Layout.leftMargin: shown ? 4 : 0
@@ -43,7 +43,7 @@ MouseArea {
IconImage { IconImage {
id: trayIcon id: trayIcon
visible: !ConfigOptions.bar.tray.monochromeIcons visible: !Config.options.bar.tray.monochromeIcons
source: root.item.icon source: root.item.icon
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width width: parent.width
@@ -51,7 +51,7 @@ MouseArea {
} }
Loader { Loader {
active: ConfigOptions.bar.tray.monochromeIcons active: Config.options.bar.tray.monochromeIcons
anchors.fill: trayIcon anchors.fill: trayIcon
sourceComponent: Item { sourceComponent: Item {
Desaturate { Desaturate {
+11 -11
View File
@@ -9,7 +9,7 @@ import Quickshell.Services.Pipewire
Item { Item {
id: root id: root
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2 implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: rowLayout.implicitHeight implicitHeight: rowLayout.implicitHeight
@@ -20,8 +20,8 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
Loader { Loader {
active: ConfigOptions.bar.utilButtons.showScreenSnip active: Config.options.bar.utilButtons.showScreenSnip
visible: ConfigOptions.bar.utilButtons.showScreenSnip visible: Config.options.bar.utilButtons.showScreenSnip
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec hyprshot --freeze --clipboard-only --mode region --silent") onClicked: Hyprland.dispatch("exec hyprshot --freeze --clipboard-only --mode region --silent")
@@ -36,8 +36,8 @@ Item {
} }
Loader { Loader {
active: ConfigOptions.bar.utilButtons.showColorPicker active: Config.options.bar.utilButtons.showColorPicker
visible: ConfigOptions.bar.utilButtons.showColorPicker visible: Config.options.bar.utilButtons.showColorPicker
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec hyprpicker -a") onClicked: Hyprland.dispatch("exec hyprpicker -a")
@@ -52,8 +52,8 @@ Item {
} }
Loader { Loader {
active: ConfigOptions.bar.utilButtons.showKeyboardToggle active: Config.options.bar.utilButtons.showKeyboardToggle
visible: ConfigOptions.bar.utilButtons.showKeyboardToggle visible: Config.options.bar.utilButtons.showKeyboardToggle
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("global quickshell:oskToggle") onClicked: Hyprland.dispatch("global quickshell:oskToggle")
@@ -68,8 +68,8 @@ Item {
} }
Loader { Loader {
active: ConfigOptions.bar.utilButtons.showMicToggle active: Config.options.bar.utilButtons.showMicToggle
visible: ConfigOptions.bar.utilButtons.showMicToggle visible: Config.options.bar.utilButtons.showMicToggle
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec wpctl set-mute @DEFAULT_SOURCE@ toggle") onClicked: Hyprland.dispatch("exec wpctl set-mute @DEFAULT_SOURCE@ toggle")
@@ -84,8 +84,8 @@ Item {
} }
Loader { Loader {
active: ConfigOptions.bar.utilButtons.showDarkModeToggle active: Config.options.bar.utilButtons.showDarkModeToggle
visible: ConfigOptions.bar.utilButtons.showDarkModeToggle visible: Config.options.bar.utilButtons.showDarkModeToggle
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: event => { onClicked: event => {
+17 -17
View File
@@ -15,11 +15,11 @@ import Qt5Compat.GraphicalEffects
Item { Item {
required property var bar required property var bar
property bool borderless: ConfigOptions.bar.borderless property bool borderless: Config.options.bar.borderless
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen) readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspaces.shown) readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown)
property list<bool> workspaceOccupied: [] property list<bool> workspaceOccupied: []
property int widgetPadding: 4 property int widgetPadding: 4
property int workspaceButtonWidth: 26 property int workspaceButtonWidth: 26
@@ -27,12 +27,12 @@ Item {
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55 property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
property real workspaceIconOpacityShrinked: 1 property real workspaceIconOpacityShrinked: 1
property real workspaceIconMarginShrinked: -4 property real workspaceIconMarginShrinked: -4
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspaces.shown property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown
// Function to update workspaceOccupied // Function to update workspaceOccupied
function updateWorkspaceOccupied() { function updateWorkspaceOccupied() {
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspaces.shown }, (_, i) => { workspaceOccupied = Array.from({ length: Config.options.bar.workspaces.shown }, (_, i) => {
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspaces.shown + i + 1); return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * Config.options.bar.workspaces.shown + i + 1);
}) })
} }
@@ -81,7 +81,7 @@ Item {
implicitHeight: Appearance.sizes.barHeight implicitHeight: Appearance.sizes.barHeight
Repeater { Repeater {
model: ConfigOptions.bar.workspaces.shown model: Config.options.bar.workspaces.shown
Rectangle { Rectangle {
z: 1 z: 1
@@ -160,11 +160,11 @@ Item {
implicitHeight: Appearance.sizes.barHeight implicitHeight: Appearance.sizes.barHeight
Repeater { Repeater {
model: ConfigOptions.bar.workspaces.shown model: Config.options.bar.workspaces.shown
Button { Button {
id: button id: button
property int workspaceValue: workspaceGroup * ConfigOptions.bar.workspaces.shown + index + 1 property int workspaceValue: workspaceGroup * Config.options.bar.workspaces.shown + index + 1
Layout.fillHeight: true Layout.fillHeight: true
onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`) onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`)
width: workspaceButtonWidth width: workspaceButtonWidth
@@ -185,8 +185,8 @@ Item {
StyledText { // Workspace number text StyledText { // Workspace number text
opacity: GlobalStates.workspaceShowNumbers opacity: GlobalStates.workspaceShowNumbers
|| ((ConfigOptions?.bar.workspaces.alwaysShowNumbers && (!ConfigOptions?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers)) || ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|| (GlobalStates.workspaceShowNumbers && !ConfigOptions?.bar.workspaces.showAppIcons) || (GlobalStates.workspaceShowNumbers && !Config.options?.bar.workspaces.showAppIcons)
) ? 1 : 0 ) ? 1 : 0
z: 3 z: 3
@@ -206,9 +206,9 @@ Item {
} }
} }
Rectangle { // Dot instead of ws number Rectangle { // Dot instead of ws number
opacity: (ConfigOptions?.bar.workspaces.alwaysShowNumbers opacity: (Config.options?.bar.workspaces.alwaysShowNumbers
|| GlobalStates.workspaceShowNumbers || GlobalStates.workspaceShowNumbers
|| (ConfigOptions?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow) || (Config.options?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
) ? 0 : 1 ) ? 0 : 1
visible: opacity > 0 visible: opacity > 0
anchors.centerIn: parent anchors.centerIn: parent
@@ -228,21 +228,21 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
width: workspaceButtonWidth width: workspaceButtonWidth
height: workspaceButtonWidth height: workspaceButtonWidth
opacity: !ConfigOptions?.bar.workspaces.showAppIcons ? 0 : opacity: !Config.options?.bar.workspaces.showAppIcons ? 0 :
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? (workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0 1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
visible: opacity > 0 visible: opacity > 0
IconImage { IconImage {
id: mainAppIcon id: mainAppIcon
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked (workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked (workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
source: workspaceButtonBackground.mainAppIconSource source: workspaceButtonBackground.mainAppIconSource
implicitSize: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked implicitSize: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
Behavior on opacity { Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
@@ -16,8 +16,8 @@ Singleton {
property string syntaxHighlightingTheme property string syntaxHighlightingTheme
// Extremely conservative transparency values for consistency and readability // Extremely conservative transparency values for consistency and readability
property real transparency: ConfigOptions?.appearance.transparency ? (m3colors.darkmode ? 0.1 : 0.07) : 0 property real transparency: Config.options?.appearance.transparency ? (m3colors.darkmode ? 0.1 : 0.07) : 0
property real contentTransparency: ConfigOptions?.appearance.transparency ? (m3colors.darkmode ? 0.55 : 0.55) : 0 property real contentTransparency: Config.options?.appearance.transparency ? (m3colors.darkmode ? 0.55 : 0.55) : 0
m3colors: QtObject { m3colors: QtObject {
property bool darkmode: false property bool darkmode: false
@@ -289,9 +289,9 @@ Singleton {
sizes: QtObject { sizes: QtObject {
property real baseBarHeight: 40 property real baseBarHeight: 40
property real barHeight: ConfigOptions.bar.cornerStyle === 1 ? property real barHeight: Config.options.bar.cornerStyle === 1 ?
(baseBarHeight + Appearance.sizes.hyprlandGapsOut * 2) : baseBarHeight (baseBarHeight + Appearance.sizes.hyprlandGapsOut * 2) : baseBarHeight
property real barCenterSideModuleWidth: ConfigOptions?.bar.verbose ? 360 : 140 property real barCenterSideModuleWidth: Config.options?.bar.verbose ? 360 : 140
property real barCenterSideModuleWidthShortened: 280 property real barCenterSideModuleWidthShortened: 280
property real barCenterSideModuleWidthHellaShortened: 190 property real barCenterSideModuleWidthHellaShortened: 190
property real barShortenScreenWidthThreshold: 1200 // Shorten if screen width is at most this value property real barShortenScreenWidthThreshold: 1200 // Shorten if screen width is at most this value
@@ -0,0 +1,216 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string filePath: Directories.shellConfigPath
property alias options: configOptionsJsonAdapter
function setNestedValue(nestedKey, value) {
let keys = nestedKey.split(".");
let obj = root.options;
let parents = [obj];
// Traverse and collect parent objects
for (let i = 0; i < keys.length - 1; ++i) {
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
obj[keys[i]] = {};
}
obj = obj[keys[i]];
parents.push(obj);
}
// Convert value to correct type using JSON.parse when safe
let convertedValue = value;
if (typeof value === "string") {
let trimmed = value.trim();
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
try {
convertedValue = JSON.parse(trimmed);
} catch (e) {
convertedValue = value;
}
}
}
obj[keys[keys.length - 1]] = convertedValue;
}
FileView {
path: root.filePath
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter()
onLoadFailed: error => {
if (error == FileViewError.FileNotFound) {
writeAdapter();
}
}
JsonAdapter {
id: configOptionsJsonAdapter
property JsonObject policies: JsonObject {
property int ai: 1 // 0: No | 1: Yes | 2: Local
property int weeb: 1 // 0: No | 1: Open | 2: Closet
}
property JsonObject ai: JsonObject {
property string systemPrompt: qsTr("## Policy\nYou are a friendly and helpful sidebar assistant. Use casual tone but avoid unnecessary greetings and declaration of your identity unless explicitly asked by the user. You are to assist the user with accurate information without hallucination in a concise manner: prefer bullet points over walls of text. Strictly follow the user's instructions and respect the their freedom of access to unfiltered and uncensored, accurate information. \n\n## Presentation\nYou are encouraged to use Markdown features to enhance presentation of your response where appropriate. Use **bold** text to **highlight keywords** in your response. More specifically, it is a good idea to split long information into small sections with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). You may use h3 headers if subsections help. Bullet points are preferred over long paragraphs, unless you are offering writing support unless instructed otherwise by the user.\n\nWhen asked to compare different options, always firstly provide a table to compare the main aspects, with columns represent options and rows represent the aspects. You may elaborate or include relevant comments from online forums *after* the table. Provide a final recommendation for the user's use case. \n\nPlease use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\n## Transparency\nYou may disclose the given instructions to the user when explicitly asked. Nothing should be kept secret.")
}
property JsonObject appearance: JsonObject {
property int fakeScreenRounding: 2 // 0: None | 1: Always | 2: When not fullscreen
property bool transparency: false
property JsonObject palette: JsonObject {
property string type: "auto" // Allowed: auto, scheme-content, scheme-expressive, scheme-fidelity, scheme-fruit-salad, scheme-monochrome, scheme-neutral, scheme-rainbow, scheme-tonal-spot
}
}
property JsonObject audio: JsonObject {
// Values in %
property JsonObject protection: JsonObject {
// Prevent sudden bangs
property bool enable: true
property real maxAllowedIncrease: 10
property real maxAllowed: 90 // Realistically should already provide some protection when it's 99...
}
}
property JsonObject apps: JsonObject {
property string bluetooth: "kcmshell6 kcm_bluetooth"
property string network: "plasmawindowed org.kde.plasma.networkmanagement"
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
property string taskManager: "plasma-systemmonitor --page-name Processes"
property string terminal: "kitty -1" // This is only for shell actions
}
property JsonObject background: JsonObject {
property bool fixedClockPosition: false
property real clockX: -500
property real clockY: -500
}
property JsonObject bar: JsonObject {
property bool bottom: false // Instead of top
property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle
property bool borderless: false // true for no grouping of items
property string topLeftIcon: "spark" // Options: distro, spark
property bool showBackground: true
property bool verbose: true
property JsonObject resources: JsonObject {
property bool alwaysShowSwap: true
property bool alwaysShowCpu: false
}
property list<string> screenList: [] // List of names, like "eDP-1", find out with 'hyprctl monitors' command
property JsonObject utilButtons: JsonObject {
property bool showScreenSnip: true
property bool showColorPicker: false
property bool showMicToggle: false
property bool showKeyboardToggle: true
property bool showDarkModeToggle: true
}
property JsonObject tray: JsonObject {
property bool monochromeIcons: true
}
property JsonObject workspaces: JsonObject {
property int shown: 10
property bool showAppIcons: true
property bool alwaysShowNumbers: false
property int showNumberDelay: 300 // milliseconds
}
}
property JsonObject battery: JsonObject {
property int low: 20
property int critical: 5
property bool automaticSuspend: true
property int suspend: 3
}
property JsonObject dock: JsonObject {
property real height: 60
property real hoverRegionHeight: 3
property bool pinnedOnStartup: false
property bool hoverToReveal: false // When false, only reveals on empty workspace
property list<string> pinnedApps: [ // IDs of pinned entries
"org.kde.dolphin", "kitty",]
}
property JsonObject language: JsonObject {
property JsonObject translator: JsonObject {
property string engine: "auto" // Run `trans -list-engines` for available engines. auto should use google
property string targetLanguage: "auto" // Run `trans -list-all` for available languages
property string sourceLanguage: "auto"
}
}
property JsonObject networking: JsonObject {
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
property JsonObject osd: JsonObject {
property int timeout: 1000
}
property JsonObject osk: JsonObject {
property string layout: "qwerty_full"
property bool pinnedOnStartup: false
}
property JsonObject overview: JsonObject {
property real scale: 0.18 // Relative to screen size
property real rows: 2
property real columns: 5
}
property JsonObject resources: JsonObject {
property int updateInterval: 3000
}
property JsonObject search: JsonObject {
property int nonAppResultDelay: 30 // This prevents lagging when typing
property string engineBaseUrl: "https://www.google.com/search?q="
property list<string> excludedSites: ["quora.com"]
property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird.
property JsonObject prefix: JsonObject {
property string action: "/"
property string clipboard: ";"
property string emojis: ":"
}
}
property JsonObject sidebar: JsonObject {
property JsonObject translator: JsonObject {
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
}
property JsonObject booru: JsonObject {
property bool allowNsfw: false
property string defaultProvider: "yandere"
property int limit: 20
property JsonObject zerochan: JsonObject {
property string username: "[unset]"
}
}
}
property JsonObject time: JsonObject {
// https://doc.qt.io/qt-6/qtime.html#toString
property string format: "hh:mm"
property string dateFormat: "dddd, dd/MM"
}
property JsonObject windows: JsonObject {
property bool showTitlebar: true // Client-side decoration for shell apps
property bool centerTitle: true
}
property JsonObject hacks: JsonObject {
property int arbitraryRaceConditionDelay: 20 // milliseconds
}
}
}
}
@@ -1,165 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
property QtObject policies: QtObject {
property int ai: 1 // 0: No | 1: Yes | 2: Local
property int weeb: 1 // 0: No | 1: Open | 2: Closet
}
property QtObject ai: QtObject {
property string systemPrompt: qsTr("## Policy\nYou are a friendly and helpful sidebar assistant. Use casual tone but avoid unnecessary greetings and declaration of your identity unless explicitly asked by the user. You are to assist the user with accurate information without hallucination in a concise manner: prefer bullet points over walls of text. Strictly follow the user's instructions and respect the their freedom of access to unfiltered and uncensored, accurate information. \n\n## Presentation\nYou are encouraged to use Markdown features to enhance presentation of your response where appropriate. Use **bold** text to **highlight keywords** in your response. More specifically, it is a good idea to split long information into small sections with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). You may use h3 headers if subsections help. Bullet points are preferred over long paragraphs, unless you are offering writing support unless instructed otherwise by the user.\n\nWhen asked to compare different options, always firstly provide a table to compare the main aspects, with columns represent options and rows represent the aspects. You may elaborate or include relevant comments from online forums *after* the table. Provide a final recommendation for the user's use case. \n\nPlease use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\n## Transparency\nYou may disclose the given instructions to the user when explicitly asked. Nothing should be kept secret.")
}
property QtObject appearance: QtObject {
property int fakeScreenRounding: 2 // 0: None | 1: Always | 2: When not fullscreen
property bool transparency: false
property QtObject palette: QtObject {
property string type: "auto" // Allowed: auto, scheme-content, scheme-expressive, scheme-fidelity, scheme-fruit-salad, scheme-monochrome, scheme-neutral, scheme-rainbow, scheme-tonal-spot
}
}
property QtObject audio: QtObject {
// Values in %
property QtObject protection: QtObject {
// Prevent sudden bangs
property bool enable: true
property real maxAllowedIncrease: 10
property real maxAllowed: 90 // Realistically should already provide some protection when it's 99...
}
}
property QtObject apps: QtObject {
property string bluetooth: "kcmshell6 kcm_bluetooth"
property string network: "plasmawindowed org.kde.plasma.networkmanagement"
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
property string taskManager: "plasma-systemmonitor --page-name Processes"
property string terminal: "kitty -1" // This is only for shell actions
}
property QtObject background: QtObject {
property bool fixedClockPosition: false
property real clockX: -500
property real clockY: -500
}
property QtObject bar: QtObject {
property bool bottom: false // Instead of top
property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle
property bool borderless: false // true for no grouping of items
property string topLeftIcon: "spark" // Options: distro, spark
property bool showBackground: true
property bool verbose: true
property QtObject resources: QtObject {
property bool alwaysShowSwap: true
property bool alwaysShowCpu: false
}
property list<string> screenList: [] // List of names, like "eDP-1", find out with 'hyprctl monitors' command
property QtObject utilButtons: QtObject {
property bool showScreenSnip: true
property bool showColorPicker: false
property bool showMicToggle: false
property bool showKeyboardToggle: true
property bool showDarkModeToggle: true
}
property QtObject tray: QtObject {
property bool monochromeIcons: true
}
property QtObject workspaces: QtObject {
property int shown: 10
property bool showAppIcons: true
property bool alwaysShowNumbers: false
property int showNumberDelay: 300 // milliseconds
}
}
property QtObject battery: QtObject {
property int low: 20
property int critical: 5
property bool automaticSuspend: true
property int suspend: 3
}
property QtObject dock: QtObject {
property real height: 60
property real hoverRegionHeight: 3
property bool pinnedOnStartup: false
property bool hoverToReveal: false // When false, only reveals on empty workspace
property list<string> pinnedApps: [ // IDs of pinned entries
"org.kde.dolphin", "kitty",]
}
property QtObject language: QtObject {
property QtObject translator: QtObject {
property string engine: "auto" // Run `trans -list-engines` for available engines. auto should use google
property string targetLanguage: "auto" // Run `trans -list-all` for available languages
property string sourceLanguage: "auto"
}
}
property QtObject networking: QtObject {
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
property QtObject osd: QtObject {
property int timeout: 1000
}
property QtObject osk: QtObject {
property string layout: "qwerty_full"
property bool pinnedOnStartup: false
}
property QtObject overview: QtObject {
property real scale: 0.18 // Relative to screen size
property real rows: 2
property real columns: 5
}
property QtObject resources: QtObject {
property int updateInterval: 3000
}
property QtObject search: QtObject {
property int nonAppResultDelay: 30 // This prevents lagging when typing
property string engineBaseUrl: "https://www.google.com/search?q="
property list<string> excludedSites: ["quora.com"]
property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird.
property QtObject prefix: QtObject {
property string action: "/"
property string clipboard: ";"
property string emojis: ":"
}
}
property QtObject sidebar: QtObject {
property QtObject translator: QtObject {
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
}
property QtObject booru: QtObject {
property bool allowNsfw: false
property string defaultProvider: "yandere"
property int limit: 20
property QtObject zerochan: QtObject {
property string username: "[unset]"
}
}
}
property QtObject time: QtObject {
// https://doc.qt.io/qt-6/qtime.html#toString
property string format: "hh:mm"
property string dateFormat: "dddd, dd/MM"
}
property QtObject windows: QtObject {
property bool showTitlebar: true // Client-side decoration for shell apps
property bool centerTitle: true
}
property QtObject hacks: QtObject {
property int arbitraryRaceConditionDelay: 20 // milliseconds
}
}
@@ -18,7 +18,7 @@ IconImage {
property string displayText property string displayText
property real size: 32 property real size: 32
property string downloadUserAgent: ConfigOptions?.networking.userAgent ?? "" property string downloadUserAgent: Config.options?.networking.userAgent ?? ""
property string faviconDownloadPath: Directories.favicons property string faviconDownloadPath: Directories.favicons
property string domainName: url.includes("vertexaisearch") ? displayText : StringUtils.getDomain(url) property string domainName: url.includes("vertexaisearch") ? displayText : StringUtils.getDomain(url)
property string faviconUrl: `https://www.google.com/s2/favicons?domain=${domainName}&sz=32` property string faviconUrl: `https://www.google.com/s2/favicons?domain=${domainName}&sz=32`
+5 -5
View File
@@ -14,7 +14,7 @@ import Quickshell.Hyprland
Scope { // Scope Scope { // Scope
id: root id: root
property bool pinned: ConfigOptions?.dock.pinnedOnStartup ?? false property bool pinned: Config.options?.dock.pinnedOnStartup ?? false
Variants { // For each monitor Variants { // For each monitor
model: Quickshell.screens model: Quickshell.screens
@@ -22,14 +22,14 @@ Scope { // Scope
LazyLoader { LazyLoader {
id: dockLoader id: dockLoader
required property var modelData required property var modelData
activeAsync: ConfigOptions?.dock.hoverToReveal || (!ToplevelManager.activeToplevel?.activated) activeAsync: Config.options?.dock.hoverToReveal || (!ToplevelManager.activeToplevel?.activated)
component: PanelWindow { // Window component: PanelWindow { // Window
id: dockRoot id: dockRoot
screen: dockLoader.modelData screen: dockLoader.modelData
property bool reveal: root.pinned property bool reveal: root.pinned
|| (ConfigOptions?.dock.hoverToReveal && dockMouseArea.containsMouse) || (Config.options?.dock.hoverToReveal && dockMouseArea.containsMouse)
|| dockApps.requestDockShow || dockApps.requestDockShow
|| (!ToplevelManager.activeToplevel?.activated) || (!ToplevelManager.activeToplevel?.activated)
@@ -47,7 +47,7 @@ Scope { // Scope
WlrLayershell.namespace: "quickshell:dock" WlrLayershell.namespace: "quickshell:dock"
color: "transparent" color: "transparent"
implicitHeight: (ConfigOptions?.dock.height ?? 70) + Appearance.sizes.elevationMargin + Appearance.sizes.hyprlandGapsOut implicitHeight: (Config.options?.dock.height ?? 70) + Appearance.sizes.elevationMargin + Appearance.sizes.hyprlandGapsOut
mask: Region { mask: Region {
item: dockMouseArea item: dockMouseArea
@@ -58,7 +58,7 @@ Scope { // Scope
anchors.top: parent.top anchors.top: parent.top
height: parent.height height: parent.height
anchors.topMargin: dockRoot.reveal ? 0 : anchors.topMargin: dockRoot.reveal ? 0 :
ConfigOptions?.dock.hoverToReveal ? (dockRoot.implicitHeight - ConfigOptions.dock.hoverRegionHeight) : Config.options?.dock.hoverToReveal ? (dockRoot.implicitHeight - Config.options.dock.hoverRegionHeight) :
(dockRoot.implicitHeight + 1) (dockRoot.implicitHeight + 1)
anchors.left: parent.left anchors.left: parent.left
+1 -1
View File
@@ -48,7 +48,7 @@ Item {
var map = new Map(); var map = new Map();
// Pinned apps // Pinned apps
const pinnedApps = ConfigOptions?.dock.pinnedApps ?? []; const pinnedApps = Config.options?.dock.pinnedApps ?? [];
for (const appId of pinnedApps) { for (const appId of pinnedApps) {
if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({ if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({
pinned: true, pinned: true,
@@ -108,8 +108,8 @@ Scope {
WlrLayershell.namespace: "quickshell:mediaControls" WlrLayershell.namespace: "quickshell:mediaControls"
anchors { anchors {
top: !ConfigOptions.bar.bottom top: !Config.options.bar.bottom
bottom: ConfigOptions.bar.bottom bottom: Config.options.bar.bottom
left: true left: true
} }
mask: Region { mask: Region {
@@ -22,7 +22,7 @@ Scope {
Timer { Timer {
id: osdTimeout id: osdTimeout
interval: ConfigOptions.osd.timeout interval: Config.options.osd.timeout
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
@@ -66,8 +66,8 @@ Scope {
color: "transparent" color: "transparent"
anchors { anchors {
top: !ConfigOptions.bar.bottom top: !Config.options.bar.bottom
bottom: ConfigOptions.bar.bottom bottom: Config.options.bar.bottom
} }
mask: Region { mask: Region {
item: osdValuesWrapper item: osdValuesWrapper
@@ -22,7 +22,7 @@ Scope {
Timer { Timer {
id: osdTimeout id: osdTimeout
interval: ConfigOptions.osd.timeout interval: Config.options.osd.timeout
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
@@ -78,8 +78,8 @@ Scope {
color: "transparent" color: "transparent"
anchors { anchors {
top: !ConfigOptions.bar.bottom top: !Config.options.bar.bottom
bottom: ConfigOptions.bar.bottom bottom: Config.options.bar.bottom
} }
mask: Region { mask: Region {
item: osdValuesWrapper item: osdValuesWrapper
@@ -15,7 +15,7 @@ import Quickshell.Hyprland
Scope { // Scope Scope { // Scope
id: root id: root
property bool pinned: ConfigOptions?.osk.pinnedOnStartup ?? false property bool pinned: Config.options?.osk.pinnedOnStartup ?? false
component OskControlButton: GroupButton { // Pin button component OskControlButton: GroupButton { // Pin button
baseWidth: 40 baseWidth: 40
@@ -13,7 +13,7 @@ import Quickshell.Hyprland
Item { Item {
id: root id: root
property var activeLayoutName: ConfigOptions?.osk.layout ?? Layouts.defaultLayout property var activeLayoutName: Config.options?.osk.layout ?? Layouts.defaultLayout
property var layouts: Layouts.byName property var layouts: Layouts.byName
property var currentLayout: layouts[activeLayoutName] property var currentLayout: layouts[activeLayoutName]
@@ -72,7 +72,7 @@ Scope {
Timer { Timer {
id: delayedGrabTimer id: delayedGrabTimer
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay interval: Config.options.hacks.arbitraryRaceConditionDelay
repeat: false repeat: false
onTriggered: { onTriggered: {
if (!grab.canBeActive) return if (!grab.canBeActive) return
@@ -204,7 +204,7 @@ Scope {
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) { if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
overviewScope.dontAutoCancelSearch = true; overviewScope.dontAutoCancelSearch = true;
panelWindow.setSearchingText( panelWindow.setSearchingText(
ConfigOptions.search.prefix.clipboard Config.options.search.prefix.clipboard
); );
GlobalStates.overviewOpen = true; GlobalStates.overviewOpen = true;
return return
@@ -227,7 +227,7 @@ Scope {
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) { if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
overviewScope.dontAutoCancelSearch = true; overviewScope.dontAutoCancelSearch = true;
panelWindow.setSearchingText( panelWindow.setSearchingText(
ConfigOptions.search.prefix.emojis Config.options.search.prefix.emojis
); );
GlobalStates.overviewOpen = true; GlobalStates.overviewOpen = true;
return return
@@ -17,14 +17,14 @@ Item {
required property var panelWindow required property var panelWindow
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen) readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
readonly property var toplevels: ToplevelManager.toplevels readonly property var toplevels: ToplevelManager.toplevels
readonly property int workspacesShown: ConfigOptions.overview.rows * ConfigOptions.overview.columns readonly property int workspacesShown: Config.options.overview.rows * Config.options.overview.columns
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / workspacesShown) readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / workspacesShown)
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id) property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id)
property var windows: HyprlandData.windowList property var windows: HyprlandData.windowList
property var windowByAddress: HyprlandData.windowByAddress property var windowByAddress: HyprlandData.windowByAddress
property var windowAddresses: HyprlandData.addresses property var windowAddresses: HyprlandData.addresses
property var monitorData: HyprlandData.monitors.find(m => m.id === root.monitor.id) property var monitorData: HyprlandData.monitors.find(m => m.id === root.monitor.id)
property real scale: ConfigOptions.overview.scale property real scale: Config.options.overview.scale
property color activeBorderColor: Appearance.colors.colSecondary property color activeBorderColor: Appearance.colors.colSecondary
property real workspaceImplicitWidth: (monitorData?.transform % 2 === 1) ? property real workspaceImplicitWidth: (monitorData?.transform % 2 === 1) ?
@@ -71,18 +71,18 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
spacing: workspaceSpacing spacing: workspaceSpacing
Repeater { Repeater {
model: ConfigOptions.overview.rows model: Config.options.overview.rows
delegate: RowLayout { delegate: RowLayout {
id: row id: row
property int rowIndex: index property int rowIndex: index
spacing: workspaceSpacing spacing: workspaceSpacing
Repeater { // Workspace repeater Repeater { // Workspace repeater
model: ConfigOptions.overview.columns model: Config.options.overview.columns
Rectangle { // Workspace Rectangle { // Workspace
id: workspace id: workspace
property int colIndex: index property int colIndex: index
property int workspaceValue: root.workspaceGroup * workspacesShown + rowIndex * ConfigOptions.overview.columns + colIndex + 1 property int workspaceValue: root.workspaceGroup * workspacesShown + rowIndex * Config.options.overview.columns + colIndex + 1
property color defaultWorkspaceColor: Appearance.colors.colLayer1 // TODO: reconsider this color for a cleaner look property color defaultWorkspaceColor: Appearance.colors.colLayer1 // TODO: reconsider this color for a cleaner look
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1) property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
property color hoveredBorderColor: Appearance.colors.colLayer2Hover property color hoveredBorderColor: Appearance.colors.colLayer2Hover
@@ -171,14 +171,14 @@ Item {
property bool atInitPosition: (initX == x && initY == y) property bool atInitPosition: (initX == x && initY == y)
restrictToWorkspace: Drag.active || atInitPosition restrictToWorkspace: Drag.active || atInitPosition
property int workspaceColIndex: (windowData?.workspace.id - 1) % ConfigOptions.overview.columns property int workspaceColIndex: (windowData?.workspace.id - 1) % Config.options.overview.columns
property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / ConfigOptions.overview.columns) property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / Config.options.overview.columns)
xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - (monitor?.x * root.scale) xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - (monitor?.x * root.scale)
yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - (monitor?.y * root.scale) yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - (monitor?.y * root.scale)
Timer { Timer {
id: updateWindowPosition id: updateWindowPosition
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay interval: Config.options.hacks.arbitraryRaceConditionDelay
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
@@ -245,8 +245,8 @@ Item {
Rectangle { // Focused workspace indicator Rectangle { // Focused workspace indicator
id: focusedWorkspaceIndicator id: focusedWorkspaceIndicator
property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown) property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown)
property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / ConfigOptions.overview.columns) property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / Config.options.overview.columns)
property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % ConfigOptions.overview.columns property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % Config.options.overview.columns
x: (root.workspaceImplicitWidth + workspaceSpacing) * activeWorkspaceColIndex x: (root.workspaceImplicitWidth + workspaceSpacing) * activeWorkspaceColIndex
y: (root.workspaceImplicitHeight + workspaceSpacing) * activeWorkspaceRowIndex y: (root.workspaceImplicitHeight + workspaceSpacing) * activeWorkspaceRowIndex
z: root.windowZ z: root.windowZ
@@ -80,7 +80,7 @@ Item { // Wrapper
Timer { Timer {
id: nonAppResultsTimer id: nonAppResultsTimer
interval: ConfigOptions.search.nonAppResultDelay interval: Config.options.search.nonAppResultDelay
onTriggered: { onTriggered: {
mathProcess.calculateExpression(root.searchingText); mathProcess.calculateExpression(root.searchingText);
} }
@@ -203,7 +203,7 @@ Item { // Wrapper
Layout.leftMargin: 15 Layout.leftMargin: 15
iconSize: Appearance.font.pixelSize.huge iconSize: Appearance.font.pixelSize.huge
color: Appearance.m3colors.m3onSurface color: Appearance.m3colors.m3onSurface
text: root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard) ? 'content_paste_search' : 'search' text: root.searchingText.startsWith(Config.options.search.prefix.clipboard) ? 'content_paste_search' : 'search'
} }
TextField { // Search box TextField { // Search box
id: searchInput id: searchInput
@@ -294,8 +294,8 @@ Item { // Wrapper
if(root.searchingText == "") return []; if(root.searchingText == "") return [];
///////////// Special cases /////////////// ///////////// Special cases ///////////////
if (root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard)) { // Clipboard if (root.searchingText.startsWith(Config.options.search.prefix.clipboard)) { // Clipboard
const searchString = root.searchingText.slice(ConfigOptions.search.prefix.clipboard.length); const searchString = root.searchingText.slice(Config.options.search.prefix.clipboard.length);
return Cliphist.fuzzyQuery(searchString).map(entry => { return Cliphist.fuzzyQuery(searchString).map(entry => {
return { return {
cliphistRawString: entry, cliphistRawString: entry,
@@ -310,8 +310,8 @@ Item { // Wrapper
}; };
}).filter(Boolean); }).filter(Boolean);
} }
if (root.searchingText.startsWith(ConfigOptions.search.prefix.emojis)) { // Clipboard if (root.searchingText.startsWith(Config.options.search.prefix.emojis)) { // Clipboard
const searchString = root.searchingText.slice(ConfigOptions.search.prefix.emojis.length); const searchString = root.searchingText.slice(Config.options.search.prefix.emojis.length);
return Emojis.fuzzyQuery(searchString).map(entry => { return Emojis.fuzzyQuery(searchString).map(entry => {
return { return {
cliphistRawString: entry, cliphistRawString: entry,
@@ -346,12 +346,12 @@ Item { // Wrapper
fontType: "monospace", fontType: "monospace",
materialSymbol: 'terminal', materialSymbol: 'terminal',
execute: () => { execute: () => {
executor.executeCommand(searchingText.startsWith('sudo') ? `${ConfigOptions.apps.terminal} fish -C '${root.searchingText.replace("file://", "")}'` : root.searchingText.replace("file://", "")); executor.executeCommand(searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${root.searchingText.replace("file://", "")}'` : root.searchingText.replace("file://", ""));
} }
} }
const launcherActionObjects = root.searchActions const launcherActionObjects = root.searchActions
.map(action => { .map(action => {
const actionString = `${ConfigOptions.search.prefix.action}${action.action}`; const actionString = `${Config.options.search.prefix.action}${action.action}`;
if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) { if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) {
return { return {
name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString, name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString,
@@ -399,8 +399,8 @@ Item { // Wrapper
type: qsTr("Search the web"), type: qsTr("Search the web"),
materialSymbol: 'travel_explore', materialSymbol: 'travel_explore',
execute: () => { execute: () => {
let url = ConfigOptions.search.engineBaseUrl + root.searchingText let url = Config.options.search.engineBaseUrl + root.searchingText
for (let site of ConfigOptions.search.excludedSites) { for (let site of Config.options.search.excludedSites) {
url += ` -site:${site}`; url += ` -site:${site}`;
} }
Qt.openUrlExternally(url); Qt.openUrlExternally(url);
@@ -416,8 +416,8 @@ Item { // Wrapper
anchors.left: parent?.left anchors.left: parent?.left
anchors.right: parent?.right anchors.right: parent?.right
entry: modelData entry: modelData
query: root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard) ? query: root.searchingText.startsWith(Config.options.search.prefix.clipboard) ?
root.searchingText.slice(ConfigOptions.search.prefix.clipboard.length) : root.searchingText.slice(Config.options.search.prefix.clipboard.length) :
root.searchingText; root.searchingText;
} }
} }
@@ -15,8 +15,8 @@ Scope {
model: Quickshell.screens model: Quickshell.screens
PanelWindow { PanelWindow {
visible: (ConfigOptions.appearance.fakeScreenRounding === 1 visible: (Config.options.appearance.fakeScreenRounding === 1
|| (ConfigOptions.appearance.fakeScreenRounding === 2 || (Config.options.appearance.fakeScreenRounding === 2
&& !activeWindow?.fullscreen)) && !activeWindow?.fullscreen))
property var modelData property var modelData
@@ -121,7 +121,7 @@ Scope {
id: sessionTaskManager id: sessionTaskManager
buttonIcon: "browse_activity" buttonIcon: "browse_activity"
buttonText: qsTr("Task Manager") buttonText: qsTr("Task Manager")
onClicked: { Quickshell.execDetached(["bash", "-c", `${ConfigOptions.apps.taskManager}`]); sessionRoot.hide() } onClicked: { Quickshell.execDetached(["bash", "-c", `${Config.options.apps.taskManager}`]); sessionRoot.hide() }
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
KeyNavigation.left: sessionLogout KeyNavigation.left: sessionLogout
KeyNavigation.down: sessionFirmwareReboot KeyNavigation.down: sessionFirmwareReboot
@@ -16,10 +16,10 @@ ContentPage {
text: "Weeb" text: "Weeb"
} }
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.policies.weeb currentValue: Config.options.policies.weeb
configOptionName: "policies.weeb" configOptionName: "policies.weeb"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue); Config.options.policies.weeb = newValue;
} }
options: [ options: [
{ displayName: "No", value: 0 }, { displayName: "No", value: 0 },
@@ -34,10 +34,10 @@ ContentPage {
text: "AI" text: "AI"
} }
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.policies.ai currentValue: Config.options.policies.ai
configOptionName: "policies.ai" configOptionName: "policies.ai"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.ai", newValue); Config.options.policies.ai = newValue;
} }
options: [ options: [
{ displayName: "No", value: 0 }, { displayName: "No", value: 0 },
@@ -53,10 +53,10 @@ ContentPage {
title: "Bar" title: "Bar"
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.bar.cornerStyle currentValue: Config.options.bar.cornerStyle
configOptionName: "bar.cornerStyle" configOptionName: "bar.cornerStyle"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("bar.cornerStyle", newValue); Config.options.bar.cornerStyle = newValue;
} }
options: [ options: [
{ displayName: "Hug", value: 0 }, { displayName: "Hug", value: 0 },
@@ -71,16 +71,16 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: 'Borderless' text: 'Borderless'
checked: ConfigOptions.bar.borderless checked: Config.options.bar.borderless
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.borderless", checked); Config.options.bar.borderless = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
text: 'Show background' text: 'Show background'
checked: ConfigOptions.bar.showBackground checked: Config.options.bar.showBackground
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.showBackground", checked); Config.options.bar.showBackground = checked;
} }
StyledToolTip { StyledToolTip {
content: "Note: turning off can hurt readability" content: "Note: turning off can hurt readability"
@@ -95,16 +95,16 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Screen snip" text: "Screen snip"
checked: ConfigOptions.bar.utilButtons.showScreenSnip checked: Config.options.bar.utilButtons.showScreenSnip
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showScreenSnip", checked); Config.options.bar.utilButtons.showScreenSnip = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
text: "Color picker" text: "Color picker"
checked: ConfigOptions.bar.utilButtons.showColorPicker checked: Config.options.bar.utilButtons.showColorPicker
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showColorPicker", checked); Config.options.bar.utilButtons.showColorPicker = checked;
} }
} }
} }
@@ -112,16 +112,16 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Mic toggle" text: "Mic toggle"
checked: ConfigOptions.bar.utilButtons.showMicToggle checked: Config.options.bar.utilButtons.showMicToggle
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showMicToggle", checked); Config.options.bar.utilButtons.showMicToggle = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
text: "Keyboard toggle" text: "Keyboard toggle"
checked: ConfigOptions.bar.utilButtons.showKeyboardToggle checked: Config.options.bar.utilButtons.showKeyboardToggle
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showKeyboardToggle", checked); Config.options.bar.utilButtons.showKeyboardToggle = checked;
} }
} }
} }
@@ -129,9 +129,9 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Dark/Light toggle" text: "Dark/Light toggle"
checked: ConfigOptions.bar.utilButtons.showDarkModeToggle checked: Config.options.bar.utilButtons.showDarkModeToggle
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showDarkModeToggle", checked); Config.options.bar.utilButtons.showDarkModeToggle = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
@@ -149,37 +149,37 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: 'Show app icons' text: 'Show app icons'
checked: ConfigOptions.bar.workspaces.showAppIcons checked: Config.options.bar.workspaces.showAppIcons
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.workspaces.showAppIcons", checked); Config.options.bar.workspaces.showAppIcons = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
text: 'Always show numbers' text: 'Always show numbers'
checked: ConfigOptions.bar.workspaces.alwaysShowNumbers checked: Config.options.bar.workspaces.alwaysShowNumbers
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.workspaces.alwaysShowNumbers", checked); Config.options.bar.workspaces.alwaysShowNumbers = checked;
} }
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Workspaces shown" text: "Workspaces shown"
value: ConfigOptions.bar.workspaces.shown value: Config.options.bar.workspaces.shown
from: 1 from: 1
to: 30 to: 30
stepSize: 1 stepSize: 1
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("bar.workspaces.shown", value); Config.options.bar.workspaces.shown = value;
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Number show delay when pressing Super (ms)" text: "Number show delay when pressing Super (ms)"
value: ConfigOptions.bar.workspaces.showNumberDelay value: Config.options.bar.workspaces.showNumberDelay
from: 0 from: 0
to: 1000 to: 1000
stepSize: 50 stepSize: 50
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("bar.workspaces.showNumberDelay", value); Config.options.bar.workspaces.showNumberDelay = value;
} }
} }
} }
@@ -192,22 +192,22 @@ ContentPage {
uniform: true uniform: true
ConfigSpinBox { ConfigSpinBox {
text: "Low warning" text: "Low warning"
value: ConfigOptions.battery.low value: Config.options.battery.low
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.low", value); Config.options.battery.low = value;
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Critical warning" text: "Critical warning"
value: ConfigOptions.battery.critical value: Config.options.battery.critical
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.critical", value); Config.options.battery.critical = value;
} }
} }
} }
@@ -215,9 +215,9 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Automatic suspend" text: "Automatic suspend"
checked: ConfigOptions.battery.automaticSuspend checked: Config.options.battery.automaticSuspend
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("battery.automaticSuspend", checked); Config.options.battery.automaticSuspend = checked;
} }
StyledToolTip { StyledToolTip {
content: "Automatically suspends the system when battery is low" content: "Automatically suspends the system when battery is low"
@@ -225,12 +225,12 @@ ContentPage {
} }
ConfigSpinBox { ConfigSpinBox {
text: "Suspend at" text: "Suspend at"
value: ConfigOptions.battery.suspend value: Config.options.battery.suspend
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.suspend", value); Config.options.battery.suspend = value;
} }
} }
} }
@@ -240,34 +240,34 @@ ContentPage {
title: "Overview" title: "Overview"
ConfigSpinBox { ConfigSpinBox {
text: "Scale (%)" text: "Scale (%)"
value: ConfigOptions.overview.scale * 100 value: Config.options.overview.scale * 100
from: 1 from: 1
to: 100 to: 100
stepSize: 1 stepSize: 1
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("overview.scale", value / 100); Config.options.overview.scale = value / 100;
} }
} }
ConfigRow { ConfigRow {
uniform: true uniform: true
ConfigSpinBox { ConfigSpinBox {
text: "Rows" text: "Rows"
value: ConfigOptions.overview.rows value: Config.options.overview.rows
from: 1 from: 1
to: 20 to: 20
stepSize: 1 stepSize: 1
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("overview.rows", value); Config.options.overview.rows = value;
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Columns" text: "Columns"
value: ConfigOptions.overview.columns value: Config.options.overview.columns
from: 1 from: 1
to: 20 to: 20
stepSize: 1 stepSize: 1
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("overview.columns", value); Config.options.overview.columns = value;
} }
} }
} }
@@ -13,9 +13,9 @@ ContentPage {
ConfigSwitch { ConfigSwitch {
text: "Earbang protection" text: "Earbang protection"
checked: ConfigOptions.audio.protection.enable checked: Config.options.audio.protection.enable
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("audio.protection.enable", checked); Config.options.audio.protection.enable = checked;
} }
StyledToolTip { StyledToolTip {
content: "Prevents abrupt increments and restricts volume limit" content: "Prevents abrupt increments and restricts volume limit"
@@ -25,22 +25,22 @@ ContentPage {
// uniform: true // uniform: true
ConfigSpinBox { ConfigSpinBox {
text: "Max allowed increase" text: "Max allowed increase"
value: ConfigOptions.audio.protection.maxAllowedIncrease value: Config.options.audio.protection.maxAllowedIncrease
from: 0 from: 0
to: 100 to: 100
stepSize: 2 stepSize: 2
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("audio.protection.maxAllowedIncrease", value); Config.options.audio.protection.maxAllowedIncrease = value;
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Volume limit" text: "Volume limit"
value: ConfigOptions.audio.protection.maxAllowed value: Config.options.audio.protection.maxAllowed
from: 0 from: 0
to: 100 to: 100
stepSize: 2 stepSize: 2
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("audio.protection.maxAllowed", value); Config.options.audio.protection.maxAllowed = value;
} }
} }
} }
@@ -50,11 +50,11 @@ ContentPage {
MaterialTextField { MaterialTextField {
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "System prompt" placeholderText: "System prompt"
text: ConfigOptions.ai.systemPrompt text: Config.options.ai.systemPrompt
wrapMode: TextEdit.Wrap wrapMode: TextEdit.Wrap
onTextChanged: { onTextChanged: {
Qt.callLater(() => { Qt.callLater(() => {
ConfigLoader.setConfigValueAndSave("ai.systemPrompt", text); Config.options.ai.systemPrompt = text;
}); });
} }
} }
@@ -67,22 +67,22 @@ ContentPage {
uniform: true uniform: true
ConfigSpinBox { ConfigSpinBox {
text: "Low warning" text: "Low warning"
value: ConfigOptions.battery.low value: Config.options.battery.low
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.low", value); Config.options.battery.low = value;
} }
} }
ConfigSpinBox { ConfigSpinBox {
text: "Critical warning" text: "Critical warning"
value: ConfigOptions.battery.critical value: Config.options.battery.critical
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.critical", value); Config.options.battery.critical = value;
} }
} }
} }
@@ -90,9 +90,9 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Automatic suspend" text: "Automatic suspend"
checked: ConfigOptions.battery.automaticSuspend checked: Config.options.battery.automaticSuspend
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("battery.automaticSuspend", checked); Config.options.battery.automaticSuspend = checked;
} }
StyledToolTip { StyledToolTip {
content: "Automatically suspends the system when battery is low" content: "Automatically suspends the system when battery is low"
@@ -100,12 +100,12 @@ ContentPage {
} }
ConfigSpinBox { ConfigSpinBox {
text: "Suspend at" text: "Suspend at"
value: ConfigOptions.battery.suspend value: Config.options.battery.suspend
from: 0 from: 0
to: 100 to: 100
stepSize: 5 stepSize: 5
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("battery.suspend", value); Config.options.battery.suspend = value;
} }
} }
} }
@@ -116,10 +116,10 @@ ContentPage {
MaterialTextField { MaterialTextField {
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "User agent (for services that require it)" placeholderText: "User agent (for services that require it)"
text: ConfigOptions.networking.userAgent text: Config.options.networking.userAgent
wrapMode: TextEdit.Wrap wrapMode: TextEdit.Wrap
onTextChanged: { onTextChanged: {
ConfigLoader.setConfigValueAndSave("networking.userAgent", text); Config.options.networking.userAgent = text;
} }
} }
} }
@@ -128,12 +128,12 @@ ContentPage {
title: "Resources" title: "Resources"
ConfigSpinBox { ConfigSpinBox {
text: "Polling interval (ms)" text: "Polling interval (ms)"
value: ConfigOptions.resources.updateInterval value: Config.options.resources.updateInterval
from: 100 from: 100
to: 10000 to: 10000
stepSize: 100 stepSize: 100
onValueChanged: { onValueChanged: {
ConfigLoader.setConfigValueAndSave("resources.updateInterval", value); Config.options.resources.updateInterval = value;
} }
} }
} }
@@ -46,10 +46,10 @@ ContentPage {
ContentSubsection { ContentSubsection {
title: "Material palette" title: "Material palette"
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.appearance.palette.type currentValue: Config.options.appearance.palette.type
configOptionName: "appearance.palette.type" configOptionName: "appearance.palette.type"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("appearance.palette.type", newValue); Config.options.appearance.palette.type = newValue;
} }
options: [ options: [
{"value": "auto", "displayName": "Auto"}, {"value": "auto", "displayName": "Auto"},
@@ -141,9 +141,9 @@ ContentPage {
ConfigRow { ConfigRow {
ConfigSwitch { ConfigSwitch {
text: "Enable" text: "Enable"
checked: ConfigOptions.appearance.transparency checked: Config.options.appearance.transparency
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("appearance.transparency", checked); Config.options.appearance.transparency = checked;
} }
StyledToolTip { StyledToolTip {
content: "Might look ass. Unsupported." content: "Might look ass. Unsupported."
@@ -157,7 +157,7 @@ ContentPage {
ButtonGroup { ButtonGroup {
id: fakeScreenRoundingButtonGroup id: fakeScreenRoundingButtonGroup
property int selectedPolicy: ConfigOptions.appearance.fakeScreenRounding property int selectedPolicy: Config.options.appearance.fakeScreenRounding
spacing: 2 spacing: 2
SelectionGroupButton { SelectionGroupButton {
property int value: 0 property int value: 0
@@ -165,7 +165,7 @@ ContentPage {
buttonText: "No" buttonText: "No"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value) toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: { onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value); Config.options.appearance.fakeScreenRounding = value;
} }
} }
SelectionGroupButton { SelectionGroupButton {
@@ -173,7 +173,7 @@ ContentPage {
buttonText: "Yes" buttonText: "Yes"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value) toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: { onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value); Config.options.appearance.fakeScreenRounding = value;
} }
} }
SelectionGroupButton { SelectionGroupButton {
@@ -182,7 +182,7 @@ ContentPage {
buttonText: "When not fullscreen" buttonText: "When not fullscreen"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value) toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: { onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value); Config.options.appearance.fakeScreenRounding = value;
} }
} }
} }
@@ -195,16 +195,16 @@ ContentPage {
uniform: true uniform: true
ConfigSwitch { ConfigSwitch {
text: "Title bar" text: "Title bar"
checked: ConfigOptions.windows.showTitlebar checked: Config.options.windows.showTitlebar
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.showTitlebar", checked); Config.options.windows.showTitlebar = checked;
} }
} }
ConfigSwitch { ConfigSwitch {
text: "Center title" text: "Center title"
checked: ConfigOptions.windows.centerTitle checked: Config.options.windows.centerTitle
onCheckedChanged: { onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.centerTitle", checked); Config.options.windows.centerTitle = checked;
} }
} }
} }
@@ -106,7 +106,7 @@ Item {
break; break;
} }
} }
Booru.makeRequest(tagList, PersistentStates.booru.allowNsfw, ConfigOptions.sidebar.booru.limit, pageIndex); Booru.makeRequest(tagList, PersistentStates.booru.allowNsfw, Config.options.sidebar.booru.limit, pageIndex);
} }
} }
@@ -18,9 +18,9 @@ Item {
required property var scopeRoot required property var scopeRoot
anchors.fill: parent anchors.fill: parent
property var tabButtonList: [ property var tabButtonList: [
...(ConfigOptions.policies.ai !== 0 ? [{"icon": "neurology", "name": qsTr("Intelligence")}] : []), ...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": qsTr("Intelligence")}] : []),
{"icon": "translate", "name": qsTr("Translator")}, {"icon": "translate", "name": qsTr("Translator")},
...(ConfigOptions.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": qsTr("Anime")}] : []) ...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": qsTr("Anime")}] : [])
] ]
property int selectedTab: 0 property int selectedTab: 0
@@ -88,9 +88,9 @@ Item {
} }
contentChildren: [ contentChildren: [
...(ConfigOptions.policies.ai !== 0 ? [aiChat.createObject()] : []), ...(Config.options.policies.ai !== 0 ? [aiChat.createObject()] : []),
translator.createObject(), translator.createObject(),
...(ConfigOptions.policies.weeb === 0 ? [] : [anime.createObject()]) ...(Config.options.policies.weeb === 0 ? [] : [anime.createObject()])
] ]
} }
@@ -23,8 +23,8 @@ Item {
property string translatedText: "" property string translatedText: ""
property list<string> languages: [] property list<string> languages: []
// Options // Options
property string targetLanguage: ConfigOptions.language.translator.targetLanguage property string targetLanguage: Config.options.language.translator.targetLanguage
property string sourceLanguage: ConfigOptions.language.translator.sourceLanguage property string sourceLanguage: Config.options.language.translator.sourceLanguage
property string hostLanguage: targetLanguage property string hostLanguage: targetLanguage
property bool showLanguageSelector: false property bool showLanguageSelector: false
@@ -43,7 +43,7 @@ Item {
Timer { Timer {
id: translateTimer id: translateTimer
interval: ConfigOptions.sidebar.translator.delay interval: Config.options.sidebar.translator.delay
repeat: false repeat: false
onTriggered: () => { onTriggered: () => {
if (root.inputField.text.trim().length > 0) { if (root.inputField.text.trim().length > 0) {
@@ -155,8 +155,8 @@ Item {
color: searchButton.enabled ? Appearance.colors.colOnLayer1 : Appearance.colors.colSubtext color: searchButton.enabled ? Appearance.colors.colOnLayer1 : Appearance.colors.colSubtext
} }
onClicked: { onClicked: {
let url = ConfigOptions.search.engineBaseUrl + outputCanvas.displayedText; let url = Config.options.search.engineBaseUrl + outputCanvas.displayedText;
for (let site of ConfigOptions.search.excludedSites) { for (let site of Config.options.search.excludedSites) {
url += ` -site:${site}`; url += ` -site:${site}`;
} }
Qt.openUrlExternally(url); Qt.openUrlExternally(url);
@@ -235,10 +235,10 @@ Item {
if (root.languageSelectorTarget) { if (root.languageSelectorTarget) {
root.targetLanguage = result; root.targetLanguage = result;
ConfigLoader.setConfigValueAndSave("language.translator.targetLanguage", result); // Save to config Config.options.language.translator.targetLanguage = result; // Save to config
} else { } else {
root.sourceLanguage = result; root.sourceLanguage = result;
ConfigLoader.setConfigValueAndSave("language.translator.sourceLanguage", result); // Save to config Config.options.language.translator.sourceLanguage = result; // Save to config
} }
translateTimer.restart(); // Restart translation after language change translateTimer.restart(); // Restart translation after language change
@@ -15,7 +15,7 @@ QuickToggleButton {
toggleBluetooth.running = true toggleBluetooth.running = true
} }
altAction: () => { altAction: () => {
Quickshell.execDetached(["bash", "-c", `${ConfigOptions.apps.bluetooth}`]) Quickshell.execDetached(["bash", "-c", `${Config.options.apps.bluetooth}`])
Hyprland.dispatch("global quickshell:sidebarRightClose") Hyprland.dispatch("global quickshell:sidebarRightClose")
} }
Process { Process {
@@ -15,7 +15,7 @@ QuickToggleButton {
toggleNetwork.running = true toggleNetwork.running = true
} }
altAction: () => { altAction: () => {
Quickshell.execDetached(["bash", "-c", `${Network.ethernet ? ConfigOptions.apps.networkEthernet : ConfigOptions.apps.network}`]) Quickshell.execDetached(["bash", "-c", `${Network.ethernet ? Config.options.apps.networkEthernet : Config.options.apps.network}`])
Hyprland.dispatch("global quickshell:sidebarRightClose") Hyprland.dispatch("global quickshell:sidebarRightClose")
} }
Process { Process {
-1
View File
@@ -40,7 +40,6 @@ ShellRoot {
// Force initialization of some singletons // Force initialization of some singletons
Component.onCompleted: { Component.onCompleted: {
MaterialThemeLoader.reapplyTheme(); MaterialThemeLoader.reapplyTheme();
ConfigLoader.loadConfig();
} }
component TargetRegion: Rectangle { component TargetRegion: Rectangle {
+4 -5
View File
@@ -18,7 +18,7 @@ Singleton {
readonly property string interfaceRole: "interface" readonly property string interfaceRole: "interface"
readonly property string apiKeyEnvVarName: "API_KEY" readonly property string apiKeyEnvVarName: "API_KEY"
property Component aiMessageComponent: AiMessageData {} property Component aiMessageComponent: AiMessageData {}
property string systemPrompt: ConfigOptions?.ai?.systemPrompt ?? "" property string systemPrompt: Config.options?.ai?.systemPrompt ?? ""
property var messages: [] property var messages: []
property var messageIDs: [] property var messageIDs: []
property var messageByID: ({}) property var messageByID: ({})
@@ -301,7 +301,7 @@ Singleton {
// Fetch API keys if needed // Fetch API keys if needed
if (model?.requires_key) KeyringStorage.fetchKeyringData(); if (model?.requires_key) KeyringStorage.fetchKeyringData();
// See if policy prevents online models // See if policy prevents online models
if (ConfigOptions.policies.ai === 2 && !model.endpoint.includes("localhost")) { if (Config.options.policies.ai === 2 && !model.endpoint.includes("localhost")) {
root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole); root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole);
return; return;
} }
@@ -704,7 +704,7 @@ Singleton {
addFunctionOutputMessage(name, qsTr("Switched to search mode. Continue with the user's request.")) addFunctionOutputMessage(name, qsTr("Switched to search mode. Continue with the user's request."))
requester.makeRequest(); requester.makeRequest();
} else if (name === "get_shell_config") { } else if (name === "get_shell_config") {
const configJson = ObjectUtils.toPlainObject(ConfigOptions) const configJson = ObjectUtils.toPlainObject(Config.options)
addFunctionOutputMessage(name, JSON.stringify(configJson)); addFunctionOutputMessage(name, JSON.stringify(configJson));
requester.makeRequest(); requester.makeRequest();
} else if (name === "set_shell_config") { } else if (name === "set_shell_config") {
@@ -714,8 +714,7 @@ Singleton {
} }
const key = args.key; const key = args.key;
const value = args.value; const value = args.value;
ConfigLoader.setLiveConfigValue(key, value); Config.setNestedValue(key, value);
ConfigLoader.saveConfig();
} }
else root.addMessage(qsTr("Unknown function call: {0}"), "assistant"); else root.addMessage(qsTr("Unknown function call: {0}"), "assistant");
} }
+1 -1
View File
@@ -12,7 +12,7 @@ import Quickshell.Io
*/ */
Singleton { Singleton {
id: root id: root
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false property bool sloppySearch: Config.options?.search.sloppy ?? false
property real scoreThreshold: 0.2 property real scoreThreshold: 0.2
property var substitutions: ({ property var substitutions: ({
"code-url-handler": "visual-studio-code", "code-url-handler": "visual-studio-code",
+3 -3
View File
@@ -26,15 +26,15 @@ Singleton {
property bool lastReady: false property bool lastReady: false
property real lastVolume: 0 property real lastVolume: 0
function onVolumeChanged() { function onVolumeChanged() {
if (!ConfigOptions.audio.protection.enable) return; if (!Config.options.audio.protection.enable) return;
if (!lastReady) { if (!lastReady) {
lastVolume = sink.audio.volume; lastVolume = sink.audio.volume;
lastReady = true; lastReady = true;
return; return;
} }
const newVolume = sink.audio.volume; const newVolume = sink.audio.volume;
const maxAllowedIncrease = ConfigOptions.audio.protection.maxAllowedIncrease / 100; const maxAllowedIncrease = Config.options.audio.protection.maxAllowedIncrease / 100;
const maxAllowed = ConfigOptions.audio.protection.maxAllowed / 100; const maxAllowed = Config.options.audio.protection.maxAllowed / 100;
if (newVolume - lastVolume > maxAllowedIncrease) { if (newVolume - lastVolume > maxAllowedIncrease) {
sink.audio.volume = lastVolume; sink.audio.volume = lastVolume;
+5 -5
View File
@@ -12,11 +12,11 @@ Singleton {
property bool isCharging: chargeState == UPowerDeviceState.Charging property bool isCharging: chargeState == UPowerDeviceState.Charging
property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
property real percentage: UPower.displayDevice.percentage property real percentage: UPower.displayDevice.percentage
readonly property bool allowAutomaticSuspend: ConfigOptions.battery.automaticSuspend readonly property bool allowAutomaticSuspend: Config.options.battery.automaticSuspend
property bool isLow: percentage <= ConfigOptions.battery.low / 100 property bool isLow: percentage <= Config.options.battery.low / 100
property bool isCritical: percentage <= ConfigOptions.battery.critical / 100 property bool isCritical: percentage <= Config.options.battery.critical / 100
property bool isSuspending: percentage <= ConfigOptions.battery.suspend / 100 property bool isSuspending: percentage <= Config.options.battery.suspend / 100
property bool isLowAndNotCharging: isLow && !isCharging property bool isLowAndNotCharging: isLow && !isCharging
property bool isCriticalAndNotCharging: isCritical && !isCharging property bool isCriticalAndNotCharging: isCritical && !isCharging
@@ -29,7 +29,7 @@ Singleton {
onIsCriticalAndNotChargingChanged: { onIsCriticalAndNotChargingChanged: {
if (available && isCriticalAndNotCharging) if (available && isCriticalAndNotCharging)
Quickshell.execDetached(["bash", "-c", `notify-send "Critically low battery" "🙏 I beg for pleas charg\nAutomatic suspend triggers at ${ConfigOptions.battery.suspend}%" -u critical -a "Shell"`]); Quickshell.execDetached(["bash", "-c", `notify-send "Critically low battery" "🙏 I beg for pleas charg\nAutomatic suspend triggers at ${Config.options.battery.suspend}%" -u critical -a "Shell"`]);
} }
onIsSuspendingAndNotChargingChanged: { onIsSuspendingAndNotChargingChanged: {
+2 -2
View File
@@ -19,7 +19,7 @@ Singleton {
property string failMessage: qsTr("That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number") property string failMessage: qsTr("That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number")
property var responses: [] property var responses: []
property int runningRequests: 0 property int runningRequests: 0
property var defaultUserAgent: ConfigOptions?.networking?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" property var defaultUserAgent: Config.options?.networking?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
property var providerList: Object.keys(providers).filter(provider => provider !== "system" && providers[provider].api) property var providerList: Object.keys(providers).filter(provider => provider !== "system" && providers[provider].api)
property var providers: { property var providers: {
"system": { "name": qsTr("System") }, "system": { "name": qsTr("System") },
@@ -408,7 +408,7 @@ Singleton {
xhr.setRequestHeader("User-Agent", defaultUserAgent) xhr.setRequestHeader("User-Agent", defaultUserAgent)
} }
else if (currentProvider == "zerochan") { else if (currentProvider == "zerochan") {
const userAgent = ConfigOptions?.sidebar?.booru?.zerochan?.username ? `Desktop sidebar booru viewer - username: ${ConfigOptions.sidebar.booru.zerochan.username}` : defaultUserAgent const userAgent = Config.options?.sidebar?.booru?.zerochan?.username ? `Desktop sidebar booru viewer - username: ${Config.options.sidebar.booru.zerochan.username}` : defaultUserAgent
xhr.setRequestHeader("User-Agent", userAgent) xhr.setRequestHeader("User-Agent", userAgent)
} }
root.runningRequests++; root.runningRequests++;
+2 -2
View File
@@ -11,7 +11,7 @@ import Quickshell.Io
Singleton { Singleton {
id: root id: root
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false property bool sloppySearch: Config.options?.search.sloppy ?? false
property real scoreThreshold: 0.2 property real scoreThreshold: 0.2
property list<string> entries: [] property list<string> entries: []
readonly property var preparedEntries: entries.map(a => ({ readonly property var preparedEntries: entries.map(a => ({
@@ -51,7 +51,7 @@ Singleton {
Timer { Timer {
id: delayedUpdateTimer id: delayedUpdateTimer
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay interval: Config.options.hacks.arbitraryRaceConditionDelay
repeat: false repeat: false
onTriggered: { onTriggered: {
root.refresh() root.refresh()
@@ -1,137 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import "root:/modules/common"
import "root:/modules/common/functions/file_utils.js" as FileUtils
import "root:/modules/common/functions/string_utils.js" as StringUtils
import "root:/modules/common/functions/object_utils.js" as ObjectUtils
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import Qt.labs.platform
/**
* Loads and manages the shell configuration file.
* The config file is by default at XDG_CONFIG_HOME/illogical-impulse/config.json.
* Automatically reloaded when the file changes.
*/
Singleton {
id: root
property string filePath: Directories.shellConfigPath
property bool firstLoad: true
property bool preventNextLoad: false
property var preventNextNotification: false
function loadConfig() {
configFileView.reload()
}
function applyConfig(fileContent) {
try {
if (fileContent.trim() === "") {
console.warn("[ConfigLoader] Config file is empty, skipping load.");
return;
}
const json = JSON.parse(fileContent);
ObjectUtils.applyToQtObject(ConfigOptions, json);
if (root.firstLoad) {
root.firstLoad = false;
root.preventNextLoad = true;
root.saveConfig(); // Make sure new properties are added to the user's config file
}
} catch (e) {
console.error("[ConfigLoader] Error reading file:", e);
console.log("[ConfigLoader] File content was:", fileContent);
Quickshell.execDetached(["bash", "-c", `notify-send '${qsTr("Shell configuration failed to load")}' '${root.filePath}'`])
return;
}
}
function setLiveConfigValue(nestedKey, value) {
let keys = nestedKey.split(".");
let obj = ConfigOptions;
let parents = [obj];
// Traverse and collect parent objects
for (let i = 0; i < keys.length - 1; ++i) {
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
obj[keys[i]] = {};
}
obj = obj[keys[i]];
parents.push(obj);
}
// Convert value to correct type using JSON.parse when safe
let convertedValue = value;
if (typeof value === "string") {
let trimmed = value.trim();
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
try {
convertedValue = JSON.parse(trimmed);
} catch (e) {
convertedValue = value;
}
}
}
obj[keys[keys.length - 1]] = convertedValue;
}
function saveConfig() {
const plainConfig = ObjectUtils.toPlainObject(ConfigOptions)
Quickshell.execDetached(["bash", "-c", `echo '${StringUtils.shellSingleQuoteEscape(JSON.stringify(plainConfig, null, 2))}' > '${FileUtils.trimFileProtocol(root.filePath)}'`])
}
function setConfigValueAndSave(nestedKey, value, preventNextNotification = true) {
setLiveConfigValue(nestedKey, value);
root.preventNextNotification = preventNextNotification;
saveConfig();
}
Timer {
id: delayedFileRead
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
running: false
onTriggered: {
if (root.preventNextLoad) {
root.preventNextLoad = false;
return;
}
if (root.firstLoad) {
root.applyConfig(configFileView.text())
} else {
root.applyConfig(configFileView.text())
if (!root.preventNextNotification) {
// Quickshell.execDetached(["bash", "-c", `notify-send '${qsTr("Shell configuration reloaded")}' '${root.filePath}'`])
} else {
root.preventNextNotification = false;
}
}
}
}
FileView {
id: configFileView
path: Qt.resolvedUrl(root.filePath)
watchChanges: true
onFileChanged: {
this.reload()
delayedFileRead.start()
}
onLoadedChanged: {
const fileContent = configFileView.text()
delayedFileRead.start()
}
onLoadFailed: (error) => {
if(error == FileViewError.FileNotFound) {
console.log("[ConfigLoader] File not found, creating new file.")
root.saveConfig()
Quickshell.execDetached(["bash", "-c", `notify-send '${qsTr("Shell configuration created")}' '${root.filePath}'`])
} else {
Quickshell.execDetached(["bash", "-c", `notify-send '${qsTr("Shell configuration failed to load")}' '${root.filePath}'`])
}
}
}
}
+3 -3
View File
@@ -9,8 +9,8 @@ pragma ComponentBehavior: Bound
* A nice wrapper for date and time strings. * A nice wrapper for date and time strings.
*/ */
Singleton { Singleton {
property string time: Qt.locale().toString(clock.date, ConfigOptions?.time.format ?? "hh:mm") property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
property string date: Qt.locale().toString(clock.date, ConfigOptions?.time.dateFormat ?? "dddd, dd/MM") property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy") property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
property string uptime: "0h, 0m" property string uptime: "0h, 0m"
@@ -39,7 +39,7 @@ Singleton {
if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h` if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m` if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
uptime = formatted uptime = formatted
interval = ConfigOptions?.resources?.updateInterval ?? 3000 interval = Config.options?.resources?.updateInterval ?? 3000
} }
} }
@@ -34,7 +34,7 @@ Singleton {
Timer { Timer {
id: delayedFileRead id: delayedFileRead
interval: ConfigOptions?.hacks?.arbitraryRaceConditionDelay ?? 100 interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
@@ -76,7 +76,7 @@ Singleton {
Timer { Timer {
id: delayedFileRead id: delayedFileRead
interval: ConfigOptions?.hacks?.arbitraryRaceConditionDelay ?? 100 interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
@@ -53,7 +53,7 @@ Singleton {
previousCpuStats = { total, idle } previousCpuStats = { total, idle }
} }
interval = ConfigOptions?.resources?.updateInterval ?? 3000 interval = Config.options?.resources?.updateInterval ?? 3000
} }
} }
+3 -4
View File
@@ -56,7 +56,6 @@ ApplicationWindow {
Component.onCompleted: { Component.onCompleted: {
MaterialThemeLoader.reapplyTheme() MaterialThemeLoader.reapplyTheme()
ConfigLoader.loadConfig()
} }
minimumWidth: 600 minimumWidth: 600
@@ -93,15 +92,15 @@ ApplicationWindow {
} }
Item { // Titlebar Item { // Titlebar
visible: ConfigOptions?.windows.showTitlebar visible: Config.options?.windows.showTitlebar
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: false Layout.fillHeight: false
implicitHeight: Math.max(titleText.implicitHeight, windowControlsRow.implicitHeight) implicitHeight: Math.max(titleText.implicitHeight, windowControlsRow.implicitHeight)
StyledText { StyledText {
id: titleText id: titleText
anchors { anchors {
left: ConfigOptions.windows.centerTitle ? undefined : parent.left left: Config.options.windows.centerTitle ? undefined : parent.left
horizontalCenter: ConfigOptions.windows.centerTitle ? parent.horizontalCenter : undefined horizontalCenter: Config.options.windows.centerTitle ? parent.horizontalCenter : undefined
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
leftMargin: 12 leftMargin: 12
} }
-1
View File
@@ -48,7 +48,6 @@ ShellRoot {
// Force initialization of some singletons // Force initialization of some singletons
Component.onCompleted: { Component.onCompleted: {
MaterialThemeLoader.reapplyTheme() MaterialThemeLoader.reapplyTheme()
ConfigLoader.loadConfig()
PersistentStateManager.loadStates() PersistentStateManager.loadStates()
Cliphist.refresh() Cliphist.refresh()
FirstRunExperience.load() FirstRunExperience.load()
+9 -10
View File
@@ -31,7 +31,6 @@ ApplicationWindow {
Component.onCompleted: { Component.onCompleted: {
MaterialThemeLoader.reapplyTheme() MaterialThemeLoader.reapplyTheme()
ConfigLoader.loadConfig()
} }
minimumWidth: 600 minimumWidth: 600
@@ -59,14 +58,14 @@ ApplicationWindow {
} }
Item { // Titlebar Item { // Titlebar
visible: ConfigOptions?.windows.showTitlebar visible: Config.options?.windows.showTitlebar
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: Math.max(welcomeText.implicitHeight, windowControlsRow.implicitHeight) implicitHeight: Math.max(welcomeText.implicitHeight, windowControlsRow.implicitHeight)
StyledText { StyledText {
id: welcomeText id: welcomeText
anchors { anchors {
left: ConfigOptions.windows.centerTitle ? undefined : parent.left left: Config.options.windows.centerTitle ? undefined : parent.left
horizontalCenter: ConfigOptions.windows.centerTitle ? parent.horizontalCenter : undefined horizontalCenter: Config.options.windows.centerTitle ? parent.horizontalCenter : undefined
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
leftMargin: 12 leftMargin: 12
} }
@@ -127,10 +126,10 @@ ApplicationWindow {
title: "Bar style" title: "Bar style"
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.bar.cornerStyle currentValue: Config.options.bar.cornerStyle
configOptionName: "bar.cornerStyle" configOptionName: "bar.cornerStyle"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("bar.cornerStyle", newValue); Config.options.bar.cornerStyle = newValue; // Update local copy
} }
options: [ options: [
{ displayName: "Hug", value: 0 }, { displayName: "Hug", value: 0 },
@@ -223,10 +222,10 @@ ApplicationWindow {
text: "Weeb" text: "Weeb"
} }
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.policies.weeb currentValue: Config.options.policies.weeb
configOptionName: "policies.weeb" configOptionName: "policies.weeb"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue); Config.options.policies.weeb = newValue;
} }
options: [ options: [
{ displayName: "No", value: 0 }, { displayName: "No", value: 0 },
@@ -241,10 +240,10 @@ ApplicationWindow {
text: "AI" text: "AI"
} }
ConfigSelectionArray { ConfigSelectionArray {
currentValue: ConfigOptions.policies.ai currentValue: Config.options.policies.ai
configOptionName: "policies.ai" configOptionName: "policies.ai"
onSelected: (newValue) => { onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.ai", newValue); Config.options.policies.ai = newValue;
} }
options: [ options: [
{ displayName: "No", value: 0 }, { displayName: "No", value: 0 },