From e46c7c0d3d1d218c0446d3e9a25128ecbf747fe6 Mon Sep 17 00:00:00 2001
From: viridivn <42524580+viridivn@users.noreply.github.com>
Date: Sun, 23 Nov 2025 15:04:49 -0500
Subject: [PATCH 001/154] add gemini 3 model
---
dots/.config/quickshell/ii/services/Ai.qml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/dots/.config/quickshell/ii/services/Ai.qml b/dots/.config/quickshell/ii/services/Ai.qml
index ccd237de8..389fb3e78 100644
--- a/dots/.config/quickshell/ii/services/Ai.qml
+++ b/dots/.config/quickshell/ii/services/Ai.qml
@@ -294,6 +294,19 @@ Singleton {
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
"api_format": "gemini",
}),
+ "gemini-3-pro": aiModelComponent.createObject(this, {
+ "name": "Gemini 3.0 Pro",
+ "icon": "google-gemini-symbolic",
+ "description": Translation.tr("Online | Google's model\nGoogle's most intelligent model with SOTA reasoning and multimodal understanding."),
+ "homepage": "https://aistudio.google.com",
+ "endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview:streamGenerateContent",
+ "model": "gemini-3-pro-preview",
+ "requires_key": true,
+ "key_id": "gemini",
+ "key_get_link": "https://aistudio.google.com/app/apikey",
+ "key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
+ "api_format": "gemini",
+ }),
"gemini-2.5-flash-lite": aiModelComponent.createObject(this, {
"name": "Gemini 2.5 Flash-Lite",
"icon": "google-gemini-symbolic",
From 07f8a72d6db605d82f3fe2e5f4fd48029c24a857 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 23 Nov 2025 21:35:43 +0100
Subject: [PATCH 002/154] wactioncenter: media controls
---
.../ii/assets/icons/fluent/next-filled.svg | 1 +
.../ii/assets/icons/fluent/next.svg | 1 +
.../ii/assets/icons/fluent/pause-filled.svg | 1 +
.../ii/assets/icons/fluent/pause.svg | 1 +
.../ii/assets/icons/fluent/play-filled.svg | 1 +
.../ii/assets/icons/fluent/play.svg | 1 +
.../assets/icons/fluent/previous-filled.svg | 1 +
.../ii/assets/icons/fluent/previous.svg | 1 +
.../ii/mediaControls/MediaControls.qml | 25 +--
.../actionCenter/ActionCenterContent.qml | 61 +++++--
.../waffle/actionCenter/MediaPaneContent.qml | 156 ++++++++++++++++++
.../actionCenter/WaffleActionCenter.qml | 5 +-
.../bluetooth/BluetoothControl.qml | 2 +-
.../actionCenter/mainPage/MainPageFooter.qml | 4 +-
.../waffle/actionCenter/wifi/WifiControl.qml | 2 +-
.../ii/modules/waffle/bar/AppButton.qml | 2 +-
.../waffle/looks/WBarAttachedPanelContent.qml | 54 ++----
...FooterButton.qml => WBorderlessButton.qml} | 0
.../ii/modules/waffle/looks/WPane.qml | 58 +++++++
.../ii/modules/waffle/looks/WStackView.qml | 6 +-
.../waffle/onScreenDisplay/OSDValue.qml | 65 ++++----
.../waffle/onScreenDisplay/WaffleOSD.qml | 5 +-
.../ii/services/MprisController.qml | 25 +++
23 files changed, 348 insertions(+), 130 deletions(-)
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/next.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/pause.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/play.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/previous.svg
create mode 100644 dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml
rename dots/.config/quickshell/ii/modules/waffle/looks/{WPanelFooterButton.qml => WBorderlessButton.qml} (100%)
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg
new file mode 100644
index 000000000..d3741963d
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/next.svg b/dots/.config/quickshell/ii/assets/icons/fluent/next.svg
new file mode 100644
index 000000000..26bdcb05e
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg
new file mode 100644
index 000000000..595435fe7
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg b/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg
new file mode 100644
index 000000000..a334eb60d
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg
new file mode 100644
index 000000000..ae2a12370
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/play.svg b/dots/.config/quickshell/ii/assets/icons/fluent/play.svg
new file mode 100644
index 000000000..777cf8903
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/play.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg
new file mode 100644
index 000000000..b994af7e1
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg b/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg
new file mode 100644
index 000000000..bb61b7779
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml b/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml
index fa60e0474..3cd620834 100644
--- a/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml
+++ b/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml
@@ -16,7 +16,7 @@ Scope {
id: root
property bool visible: false
readonly property MprisPlayer activePlayer: MprisController.activePlayer
- readonly property var realPlayers: Mpris.players.values.filter(player => isRealPlayer(player))
+ readonly property var realPlayers: MprisController.players
readonly property var meaningfulPlayers: filterDuplicatePlayers(realPlayers)
readonly property real osdWidth: Appearance.sizes.osdWidth
readonly property real widgetWidth: Appearance.sizes.mediaControlsWidth
@@ -24,27 +24,6 @@ Scope {
property real popupRounding: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1
property list visualizerPoints: []
- property bool hasPlasmaIntegration: false
- Process {
- id: plasmaIntegrationAvailabilityCheckProc
- running: true
- command: ["bash", "-c", "command -v plasma-browser-integration-host"]
- onExited: (exitCode, exitStatus) => {
- root.hasPlasmaIntegration = (exitCode === 0);
- }
- }
- function isRealPlayer(player) {
- if (!Config.options.media.filterDuplicatePlayers) {
- return true;
- }
- return (
- // Remove unecessary native buses from browsers if there's plasma integration
- !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.firefox')) && !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) &&
- // playerctld just copies other buses and we don't need duplicates
- !player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') &&
- // Non-instance mpd bus
- !(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd')));
- }
function filterDuplicatePlayers(players) {
let filtered = [];
let used = new Set();
@@ -96,7 +75,7 @@ Scope {
id: mediaControlsLoader
active: GlobalStates.mediaControlsOpen
onActiveChanged: {
- if (!mediaControlsLoader.active && Mpris.players.values.filter(player => isRealPlayer(player)).length === 0) {
+ if (!mediaControlsLoader.active && root.realPlayers.length === 0) {
GlobalStates.mediaControlsOpen = false;
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
index 4d45df92e..284f72013 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
@@ -1,3 +1,4 @@
+pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -12,28 +13,52 @@ import qs.modules.waffle.actionCenter.mainPage
WBarAttachedPanelContent {
id: root
- contentItem: WStackView {
- id: stackView
- anchors.fill: parent
- implicitWidth: initItem.implicitWidth
- implicitHeight: initItem.implicitHeight
-
- initialItem: PageColumn {
- id: initItem
- MainPageBody {}
- Separator {}
- MainPageFooter {}
+ readonly property bool barAtBottom: Config.options.waffles.bar.bottom
+
+ contentItem: Column {
+ // This somewhat sophisticated anchoring is needed to make opening anim not jump abruptly when stuff appear
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: root.barAtBottom ? undefined : parent.top
+ bottom: root.barAtBottom ? parent.bottom : undefined
+ margins: root.visualMargin
}
+ spacing: 12
- Component.onCompleted: {
- ActionCenterContext.stackView = this
+ WPane {
+ visible: MprisController.activePlayer != null && MprisController.isRealPlayer(MprisController.activePlayer)
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ contentItem: MediaPaneContent {}
}
+ WPane {
+ contentItem: WStackView {
+ id: stackView
+ anchors.fill: parent
+ implicitWidth: initItem.implicitWidth
+ implicitHeight: initItem.implicitHeight
- MouseArea {
- anchors.fill: parent
- acceptedButtons: Qt.BackButton
- onClicked: {
- ActionCenterContext.back()
+ initialItem: PageColumn {
+ id: initItem
+ MainPageBody {}
+ Separator {}
+ MainPageFooter {}
+ }
+
+ Component.onCompleted: {
+ ActionCenterContext.stackView = this;
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.BackButton
+ onClicked: {
+ ActionCenterContext.back();
+ }
+ }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml
new file mode 100644
index 000000000..5c4c6df97
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml
@@ -0,0 +1,156 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Layouts
+import Qt5Compat.GraphicalEffects
+import Quickshell
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.common.widgets
+import qs.modules.waffle.looks
+
+Rectangle {
+ id: root
+ implicitHeight: 176
+ implicitWidth: 358
+ color: Looks.colors.bgPanelBody
+ anchors.fill: parent
+
+ readonly property var activePlayer: MprisController.activePlayer
+
+ Column {
+ anchors {
+ fill: parent
+ leftMargin: 23
+ rightMargin: 23
+ topMargin: 16
+ bottomMargin: 20
+ }
+ spacing: 25
+
+ AppInfoRow {
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ TrackInfoRow {
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ ControlButtonsRow {
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ component AppInfoRow: RowLayout {
+ id: appInfo
+ spacing: 8
+
+ property var desktopEntry: {
+ const desktopEntryString = root.activePlayer?.desktopEntry ?? "";
+ return DesktopEntries.byId(desktopEntryString);
+ }
+
+ FluentIcon {
+ implicitSize: 20
+ icon: appInfo.desktopEntry?.icon || "music-note-2"
+ monochrome: !appInfo.desktopEntry?.icon
+ }
+
+ WText {
+ Layout.fillWidth: true
+ text: appInfo.desktopEntry?.name ?? Translation.tr("Media")
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight
+ }
+ }
+
+ component TrackInfoRow: RowLayout {
+ spacing: 16
+
+ ColumnLayout {
+ id: trackInfo
+ Layout.fillWidth: true
+ spacing: 0
+
+ WText {
+ Layout.fillWidth: true
+ font.weight: Looks.font.weight.strong
+ font.pixelSize: Looks.font.pixelSize.large
+ elide: Text.ElideRight
+ text: StringUtils.cleanMusicTitle(root.activePlayer?.trackTitle) || Translation.tr("Unknown Title")
+ }
+
+ WText {
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ text: root.activePlayer?.trackArtist || Translation.tr("Unknown Artist")
+ }
+ }
+
+ StyledImage {
+ id: artImage
+ Layout.preferredWidth: 58
+ Layout.preferredHeight: trackInfo.implicitHeight
+ source: MprisController.activeTrack?.artUrl || ""
+ fillMode: Image.PreserveAspectFit
+
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Item {
+ width: artImage.width
+ height: artImage.height
+ Rectangle {
+ anchors.centerIn: parent
+ width: artImage.paintedWidth
+ height: artImage.paintedHeight
+ radius: Looks.radius.medium
+ }
+ }
+ }
+ }
+ }
+
+ component ControlButtonsRow: RowLayout {
+ spacing: 26
+
+ MediaControlButton {
+ iconName: "previous"
+ enabled: root.activePlayer?.canGoPrevious ?? false
+ onClicked: root.activePlayer?.previous()
+ }
+ MediaControlButton {
+ readonly property bool playing: root.activePlayer?.isPlaying ?? false
+ iconName: playing ? "pause" : "play"
+ enabled: (playing && root.activePlayer?.canPause) || (!playing && root.activePlayer?.canPlay)
+ onClicked: root.activePlayer?.togglePlaying()
+ }
+ MediaControlButton {
+ iconName: "next"
+ enabled: root.activePlayer?.canGoNext ?? false
+ onClicked: root.activePlayer?.next()
+ }
+ }
+
+ component MediaControlButton: WBorderlessButton {
+ id: controlButton
+ required property string iconName
+ implicitHeight: 40
+ implicitWidth: 40
+
+ contentItem: Item {
+ FluentIcon {
+ anchors.centerIn: parent
+ icon: controlButton.iconName
+ monochrome: true
+ filled: true
+ implicitSize: 18
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
index 174b7851f..8fe33fa47 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
@@ -35,8 +35,8 @@ Scope {
right: true
}
- implicitWidth: content.implicitWidth + content.visualMargin * 2
- implicitHeight: content.implicitHeight + content.visualMargin * 2
+ implicitWidth: content.implicitWidth
+ implicitHeight: content.implicitHeight
HyprlandFocusGrab {
id: focusGrab
@@ -55,7 +55,6 @@ Scope {
ActionCenterContent {
id: content
anchors.fill: parent
- anchors.margins: visualMargin
focus: true
Keys.onPressed: event => { // Esc to close
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
index c8d3a036a..e0e6327a6 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
@@ -110,7 +110,7 @@ Item {
Quickshell.execDetached(["bash", "-c", Config.options.apps.bluetooth]);
}
}
- WPanelFooterButton {
+ WBorderlessButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml
index 1190bd38e..3d5c8d882 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml
@@ -11,7 +11,7 @@ import qs.modules.waffle.actionCenter
FooterRectangle {
// Battery button
- WPanelFooterButton {
+ WBorderlessButton {
visible: Battery.available
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
@@ -36,7 +36,7 @@ FooterRectangle {
}
// Settings button
- WPanelFooterButton {
+ WBorderlessButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
index 6f07462be..e6c91292a 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
@@ -100,7 +100,7 @@ Item {
Quickshell.execDetached(["bash", "-c", Config.options.apps.network]);
}
}
- WPanelFooterButton {
+ WBorderlessButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
index 9d8d323fe..20af517fe 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
@@ -54,7 +54,7 @@ BarButton {
contentItem: Item {
id: contentItem
- anchors.centerIn: background
+ anchors.centerIn: root.background
implicitHeight: iconWidget.implicitHeight
implicitWidth: iconWidget.implicitWidth
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
index 3035a6511..657897ef1 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
@@ -12,8 +12,6 @@ Item {
signal closed()
- property alias border: borderRect
- property alias borderColor: borderRect.border.color
required property Item contentItem
property real visualMargin: 12
property int closeAnimDuration: 150
@@ -24,32 +22,19 @@ Item {
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
- implicitHeight: borderRect.implicitHeight
- implicitWidth: borderRect.implicitWidth
-
- WRectangularShadow {
- target: borderRect
- }
-
- Rectangle {
- id: borderRect
- z: 1
-
- color: "transparent"
- radius: Looks.radius.large
- border.color: Looks.colors.bg2Border
- border.width: 1
- implicitWidth: contentItem.implicitWidth + border.width * 2
- implicitHeight: contentItem.implicitHeight + border.width * 2
+ implicitHeight: contentItem.implicitHeight + visualMargin * 2
+ implicitWidth: contentItem.implicitWidth + visualMargin * 2
+ Item {
+ id: panelContent
anchors {
left: parent.left
right: parent.right
top: root.barAtBottom ? undefined : parent.top
bottom: root.barAtBottom ? parent.bottom : undefined
// Opening anim
- bottomMargin: root.barAtBottom ? sourceEdgeMargin : 0
- topMargin: root.barAtBottom ? 0 : sourceEdgeMargin
+ bottomMargin: root.barAtBottom ? sourceEdgeMargin : root.visualMargin
+ topMargin: root.barAtBottom ? root.visualMargin : sourceEdgeMargin
}
Component.onCompleted: {
@@ -59,9 +44,9 @@ Item {
property real sourceEdgeMargin: -(implicitHeight + root.visualMargin)
PropertyAnimation {
id: openAnim
- target: borderRect
+ target: panelContent
property: "sourceEdgeMargin"
- to: 0
+ to: root.visualMargin
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
@@ -69,7 +54,7 @@ Item {
SequentialAnimation {
id: closeAnim
PropertyAnimation {
- target: borderRect
+ target: panelContent
property: "sourceEdgeMargin"
to: -(implicitHeight + root.visualMargin)
duration: root.closeAnimDuration
@@ -82,23 +67,8 @@ Item {
}
}
}
- }
-
- Item {
- id: contentArea
- z: 0
- anchors.fill: borderRect
- anchors.margins: borderRect.border.width
- implicitWidth: contentItem.implicitWidth
- implicitHeight: contentItem.implicitHeight
- layer.enabled: true
- layer.effect: OpacityMask {
- maskSource: Rectangle {
- width: contentArea.width
- height: contentArea.height
- radius: borderRect.radius - borderRect.border.width
- }
- }
+ implicitWidth: root.contentItem.implicitWidth
+ implicitHeight: root.contentItem.implicitHeight
children: [root.contentItem]
- }
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPanelFooterButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml
similarity index 100%
rename from dots/.config/quickshell/ii/modules/waffle/looks/WPanelFooterButton.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
new file mode 100644
index 000000000..806afcd37
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
@@ -0,0 +1,58 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Layouts
+import Qt5Compat.GraphicalEffects
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.waffle.looks
+
+Item {
+ id: root
+ required property Item contentItem
+ property real radius: Looks.radius.large
+ property alias border: borderRect
+ property alias borderColor: borderRect.border.color
+
+ implicitWidth: contentItem.implicitWidth
+ implicitHeight: contentItem.implicitHeight
+
+ WRectangularShadow {
+ target: borderRect
+ }
+
+ Rectangle {
+ id: borderRect
+ z: 1
+
+ color: "transparent"
+ radius: root.radius
+ border.color: Looks.colors.bg2Border
+ border.width: 1
+ implicitWidth: contentItem.implicitWidth + border.width * 2
+ implicitHeight: contentItem.implicitHeight + border.width * 2
+ anchors.fill: contentRect
+ anchors.margins: -border.width
+ }
+
+ Rectangle {
+ id: contentRect
+ anchors.centerIn: parent
+ z: 0
+
+ color: Looks.colors.bgPanelFooterBase
+ implicitWidth: contentItem.implicitWidth
+ implicitHeight: contentItem.implicitHeight
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Rectangle {
+ id: contentAreaMask
+ width: contentRect.width
+ height: contentRect.height
+ radius: root.radius - borderRect.border.width
+ }
+ }
+ children: [root.contentItem]
+ }
+}
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml
index 218ec15fa..b566c91ab 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml
@@ -11,11 +11,7 @@ StackView {
property list fadeBezierCurve: Looks.transition.easing.bezierCurve.easeInOut
clip: true
- property alias color: background.color
- background: Rectangle {
- id: background
- color: Looks.colors.bgPanelFooterBase
- }
+ background: null
pushEnter: Transition {
XAnimator {
diff --git a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml
index 8d48a6f92..32db99479 100644
--- a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml
@@ -13,7 +13,6 @@ WBarAttachedPanelContent {
required property string iconName
property real value
property bool showNumber: true
- borderColor: Looks.colors.ambientShadow
property Timer timer: Timer {
id: autoCloseTimer
@@ -21,44 +20,48 @@ WBarAttachedPanelContent {
interval: Config.options.osd.timeout
repeat: false
onTriggered: {
- root.close()
+ root.close();
}
}
- contentItem: Rectangle {
+ contentItem: WPane {
anchors.centerIn: parent
- color: Looks.colors.bg1Base
- radius: Looks.radius.medium
- implicitWidth: root.showNumber ? 192 : 170
- implicitHeight: 46
-
- RowLayout {
- id: contentRow
- anchors.fill: parent
- anchors.margins: 12
+ borderColor: Looks.colors.ambientShadow
- spacing: 12
+ contentItem: Item {
+ // color: Looks.colors.bg1Base
+ // radius: Looks.radius.medium
+ implicitWidth: root.showNumber ? 192 : 170
+ implicitHeight: 46
- FluentIcon {
- Layout.alignment: Qt.AlignVCenter
- icon: root.iconName
- implicitSize: 18
- }
+ RowLayout {
+ id: contentRow
+ anchors.fill: parent
+ anchors.margins: 12
- WProgressBar {
- id: progressBar
- value: root.value
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignVCenter
- Layout.rightMargin: root.showNumber ? 0 : 3
- }
+ spacing: 12
- WTextWithFixedWidth {
- visible: root.showNumber
- text: Math.round(root.value * 100)
- // longestText: "100"
- implicitWidth: 16
- horizontalAlignment: Text.AlignHCenter
+ FluentIcon {
+ Layout.alignment: Qt.AlignVCenter
+ icon: root.iconName
+ implicitSize: 18
+ }
+
+ WProgressBar {
+ id: progressBar
+ value: root.value
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ Layout.rightMargin: root.showNumber ? 0 : 3
+ }
+
+ WTextWithFixedWidth {
+ visible: root.showNumber
+ text: Math.round(root.value * 100)
+ // longestText: "100"
+ implicitWidth: 16
+ horizontalAlignment: Text.AlignHCenter
+ }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml
index f2f06b2ae..569ed4f44 100644
--- a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml
@@ -104,13 +104,12 @@ Scope {
item: osdIndicatorLoader
}
- implicitWidth: osdIndicatorLoader.implicitWidth + osdIndicatorLoader.item.visualMargin * 2
- implicitHeight: osdIndicatorLoader.implicitHeight + osdIndicatorLoader.item.visualMargin * 2
+ implicitWidth: osdIndicatorLoader.implicitWidth
+ implicitHeight: osdIndicatorLoader.implicitHeight
Loader {
id: osdIndicatorLoader
anchors.fill: parent
- anchors.margins: item.visualMargin
source: root.indicators.find(i => i.id === root.currentIndicator)?.sourceUrl
Connections {
diff --git a/dots/.config/quickshell/ii/services/MprisController.qml b/dots/.config/quickshell/ii/services/MprisController.qml
index 1dc42da2b..02151f1c1 100644
--- a/dots/.config/quickshell/ii/services/MprisController.qml
+++ b/dots/.config/quickshell/ii/services/MprisController.qml
@@ -9,12 +9,14 @@ import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Mpris
+import qs.modules.common
/**
* A service that provides easy access to the active Mpris player.
*/
Singleton {
id: root;
+ property list players: Mpris.players.values.filter(player => isRealPlayer(player));
property MprisPlayer trackedPlayer: null;
property MprisPlayer activePlayer: trackedPlayer ?? Mpris.players.values[0] ?? null;
signal trackChanged(reverse: bool);
@@ -23,6 +25,29 @@ Singleton {
property var activeTrack;
+ property bool hasPlasmaIntegration: false
+ Process {
+ id: plasmaIntegrationAvailabilityCheckProc
+ running: true
+ command: ["bash", "-c", "command -v plasma-browser-integration-host"]
+ onExited: (exitCode, exitStatus) => {
+ root.hasPlasmaIntegration = (exitCode === 0);
+ }
+ }
+ function isRealPlayer(player) {
+ if (!Config.options.media.filterDuplicatePlayers) {
+ return true;
+ }
+ return (
+ // Remove unecessary native buses from browsers if there's plasma integration
+ !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.firefox')) && !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) &&
+ // playerctld just copies other buses and we don't need duplicates
+ !player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') &&
+ // Non-instance mpd bus
+ !(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd')));
+ }
+
+ // Original stuff from fox below
Instantiator {
model: Mpris.players;
From 19ba7dac48f06848f168387d6011c1ab97677ba7 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 23 Nov 2025 21:38:50 +0100
Subject: [PATCH 003/154] overlay: recorder: fix open folder button missing
text
---
.../quickshell/ii/modules/ii/overlay/recorder/Recorder.qml | 1 +
1 file changed, 1 insertion(+)
diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/recorder/Recorder.qml b/dots/.config/quickshell/ii/modules/ii/overlay/recorder/Recorder.qml
index 9efa37e60..812884127 100644
--- a/dots/.config/quickshell/ii/modules/ii/overlay/recorder/Recorder.qml
+++ b/dots/.config/quickshell/ii/modules/ii/overlay/recorder/Recorder.qml
@@ -3,6 +3,7 @@ import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
+import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.ii.overlay
From 25816662f8e744abb85f4b7f544e049c7c7d6260 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 23 Nov 2025 21:40:44 +0100
Subject: [PATCH 004/154] wactioncenter: fix wrong gap from bar
---
.../ii/modules/waffle/actionCenter/ActionCenterContent.qml | 1 +
1 file changed, 1 insertion(+)
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
index 284f72013..d01502444 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
@@ -23,6 +23,7 @@ WBarAttachedPanelContent {
top: root.barAtBottom ? undefined : parent.top
bottom: root.barAtBottom ? parent.bottom : undefined
margins: root.visualMargin
+ bottomMargin: 0
}
spacing: 12
From 996579729d115b72c12ad50e7f763595d53f375d Mon Sep 17 00:00:00 2001
From: viridivn <42524580+viridivn@users.noreply.github.com>
Date: Sun, 23 Nov 2025 16:03:56 -0500
Subject: [PATCH 005/154] no abbreviations
---
dots/.config/quickshell/ii/services/Ai.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dots/.config/quickshell/ii/services/Ai.qml b/dots/.config/quickshell/ii/services/Ai.qml
index 389fb3e78..d5ca44035 100644
--- a/dots/.config/quickshell/ii/services/Ai.qml
+++ b/dots/.config/quickshell/ii/services/Ai.qml
@@ -297,7 +297,7 @@ Singleton {
"gemini-3-pro": aiModelComponent.createObject(this, {
"name": "Gemini 3.0 Pro",
"icon": "google-gemini-symbolic",
- "description": Translation.tr("Online | Google's model\nGoogle's most intelligent model with SOTA reasoning and multimodal understanding."),
+ "description": Translation.tr("Online | Google's model\nGoogle's most intelligent model with state-of-the-art reasoning and multimodal understanding."),
"homepage": "https://aistudio.google.com",
"endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview:streamGenerateContent",
"model": "gemini-3-pro-preview",
From 0703429393e17a834367722aa0d60c53dfb4f2a5 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sun, 23 Nov 2025 22:27:17 +0100
Subject: [PATCH 006/154] Revert "Add Gemini 3 Pro to model list"
---
dots/.config/quickshell/ii/services/Ai.qml | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/dots/.config/quickshell/ii/services/Ai.qml b/dots/.config/quickshell/ii/services/Ai.qml
index d5ca44035..ccd237de8 100644
--- a/dots/.config/quickshell/ii/services/Ai.qml
+++ b/dots/.config/quickshell/ii/services/Ai.qml
@@ -294,19 +294,6 @@ Singleton {
"key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
"api_format": "gemini",
}),
- "gemini-3-pro": aiModelComponent.createObject(this, {
- "name": "Gemini 3.0 Pro",
- "icon": "google-gemini-symbolic",
- "description": Translation.tr("Online | Google's model\nGoogle's most intelligent model with state-of-the-art reasoning and multimodal understanding."),
- "homepage": "https://aistudio.google.com",
- "endpoint": "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview:streamGenerateContent",
- "model": "gemini-3-pro-preview",
- "requires_key": true,
- "key_id": "gemini",
- "key_get_link": "https://aistudio.google.com/app/apikey",
- "key_get_description": Translation.tr("**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key"),
- "api_format": "gemini",
- }),
"gemini-2.5-flash-lite": aiModelComponent.createObject(this, {
"name": "Gemini 2.5 Flash-Lite",
"icon": "google-gemini-symbolic",
From e6f36114bd53c71448390626d6334ed6043c5b0c Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 24 Nov 2025 10:18:05 +0100
Subject: [PATCH 007/154] waffles: notif center: calendar header and focus
---
.../ii/assets/icons/fluent/add-filled.svg | 1 +
.../quickshell/ii/assets/icons/fluent/add.svg | 1 +
.../ii/assets/icons/fluent/stop-filled.svg | 1 +
.../ii/assets/icons/fluent/stop.svg | 1 +
.../assets/icons/fluent/subtract-filled.svg | 1 +
.../ii/assets/icons/fluent/subtract.svg | 1 +
.../actionCenter/ActionCenterContent.qml | 15 ++--
.../actionCenter/WaffleActionCenter.qml | 13 +--
.../bluetooth/BluetoothControl.qml | 4 +-
.../nightLight/NightLightControl.qml | 4 +-
.../volumeControl/VolumeControl.qml | 8 +-
.../waffle/actionCenter/wifi/WifiControl.qml | 4 +-
.../{actionCenter => looks}/BodyRectangle.qml | 0
.../FooterMoreButton.qml | 0
.../FooterRectangle.qml | 2 +-
.../ii/modules/waffle/looks/Looks.qml | 6 +-
.../waffle/looks/WBarAttachedPanelContent.qml | 68 ++++++++++-----
.../modules/waffle/looks/WBorderedButton.qml | 18 ++++
.../ii/modules/waffle/looks/WPane.qml | 4 +-
.../WPanelPageColumn.qml} | 0
.../WPanelSeparator.qml} | 0
.../notificationCenter/CalendarHeader.qml | 51 +++++++++++
.../notificationCenter/CalendarView.qml | 23 +++++
.../waffle/notificationCenter/FocusFooter.qml | 87 +++++++++++++++++++
.../NotificationCenterContent.qml | 57 ++++++++++++
.../SmallBorderedIconButton.qml | 18 ++++
.../WaffleNotificationCenter.qml | 85 ++++++++++++++++++
.../quickshell/ii/services/DateTime.qml | 2 +-
dots/.config/quickshell/ii/shell.qml | 4 +-
29 files changed, 420 insertions(+), 59 deletions(-)
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/add-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/add.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/stop-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/stop.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/subtract-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/subtract.svg
rename dots/.config/quickshell/ii/modules/waffle/{actionCenter => looks}/BodyRectangle.qml (100%)
rename dots/.config/quickshell/ii/modules/waffle/{actionCenter => looks}/FooterMoreButton.qml (100%)
rename dots/.config/quickshell/ii/modules/waffle/{actionCenter => looks}/FooterRectangle.qml (92%)
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
rename dots/.config/quickshell/ii/modules/waffle/{actionCenter/PageColumn.qml => looks/WPanelPageColumn.qml} (100%)
rename dots/.config/quickshell/ii/modules/waffle/{actionCenter/Separator.qml => looks/WPanelSeparator.qml} (100%)
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/WaffleNotificationCenter.qml
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/add-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/add-filled.svg
new file mode 100644
index 000000000..6b1a81835
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/add-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/add.svg b/dots/.config/quickshell/ii/assets/icons/fluent/add.svg
new file mode 100644
index 000000000..c983f3518
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/add.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/stop-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/stop-filled.svg
new file mode 100644
index 000000000..ef8a91225
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/stop-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/stop.svg b/dots/.config/quickshell/ii/assets/icons/fluent/stop.svg
new file mode 100644
index 000000000..26eb3ea04
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/stop.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/subtract-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/subtract-filled.svg
new file mode 100644
index 000000000..128a7f96b
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/subtract-filled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/subtract.svg b/dots/.config/quickshell/ii/assets/icons/fluent/subtract.svg
new file mode 100644
index 000000000..3e1e2471c
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/subtract.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
index d01502444..b69666660 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
@@ -15,7 +15,7 @@ WBarAttachedPanelContent {
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
- contentItem: Column {
+ contentItem: ColumnLayout {
// This somewhat sophisticated anchoring is needed to make opening anim not jump abruptly when stuff appear
anchors {
left: parent.left
@@ -28,24 +28,21 @@ WBarAttachedPanelContent {
spacing: 12
WPane {
- visible: MprisController.activePlayer != null && MprisController.isRealPlayer(MprisController.activePlayer)
- anchors {
- left: parent.left
- right: parent.right
- }
+ opacity: (MprisController.activePlayer != null && MprisController.isRealPlayer(MprisController.activePlayer)) ? 1 : 0
+ Layout.fillWidth: true
contentItem: MediaPaneContent {}
}
WPane {
+ Layout.fillWidth: true
contentItem: WStackView {
id: stackView
- anchors.fill: parent
implicitWidth: initItem.implicitWidth
implicitHeight: initItem.implicitHeight
- initialItem: PageColumn {
+ initialItem: WPanelPageColumn {
id: initItem
MainPageBody {}
- Separator {}
+ WPanelSeparator {}
MainPageFooter {}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
index 8fe33fa47..56fbedda3 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
@@ -15,12 +15,12 @@ Scope {
target: GlobalStates
function onSidebarLeftOpenChanged() {
- if (GlobalStates.sidebarLeftOpen) barLoader.active = true;
+ if (GlobalStates.sidebarLeftOpen) panelLoader.active = true;
}
}
Loader {
- id: barLoader
+ id: panelLoader
active: GlobalStates.sidebarLeftOpen
sourceComponent: PanelWindow {
id: panelWindow
@@ -56,16 +56,9 @@ Scope {
id: content
anchors.fill: parent
- focus: true
- Keys.onPressed: event => { // Esc to close
- if (event.key === Qt.Key_Escape) {
- content.close()
- }
- }
-
onClosed: {
GlobalStates.sidebarLeftOpen = false;
- barLoader.active = false;
+ panelLoader.active = false;
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
index e0e6327a6..72f442b87 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml
@@ -23,7 +23,7 @@ Item {
Bluetooth.defaultAdapter.discovering = false;
}
- PageColumn {
+ WPanelPageColumn {
anchors.fill: parent
BodyRectangle {
@@ -96,7 +96,7 @@ Item {
}
}
- Separator {}
+ WPanelSeparator {}
FooterRectangle {
FooterMoreButton {
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/nightLight/NightLightControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/nightLight/NightLightControl.qml
index 71630295c..591e56399 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/nightLight/NightLightControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/nightLight/NightLightControl.qml
@@ -24,7 +24,7 @@ Item {
Bluetooth.defaultAdapter.discovering = false;
}
- PageColumn {
+ WPanelPageColumn {
anchors.fill: parent
BodyRectangle {
@@ -61,7 +61,7 @@ Item {
}
}
- Separator {}
+ WPanelSeparator {}
FooterRectangle {}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/volumeControl/VolumeControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/volumeControl/VolumeControl.qml
index b3e97a78e..52fe9ab3d 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/volumeControl/VolumeControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/volumeControl/VolumeControl.qml
@@ -14,7 +14,7 @@ Item {
id: root
property bool output: true
- PageColumn {
+ WPanelPageColumn {
anchors.fill: parent
BodyRectangle {
@@ -48,7 +48,7 @@ Item {
}
}
- Separator {}
+ WPanelSeparator {}
FooterRectangle {
WButton {
@@ -103,7 +103,7 @@ Item {
}
}
- Separator {
+ WPanelSeparator {
visible: EasyEffects.available && root.output
color: Looks.colors.bg2Hover
}
@@ -129,7 +129,7 @@ Item {
onClicked: EasyEffects.enable()
}
- Separator {
+ WPanelSeparator {
color: Looks.colors.bg2Hover
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
index e6c91292a..c90d06fc0 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml
@@ -19,7 +19,7 @@ Item {
Network.rescanWifi();
}
- PageColumn {
+ WPanelPageColumn {
anchors.fill: parent
BodyRectangle {
@@ -86,7 +86,7 @@ Item {
}
}
- Separator {}
+ WPanelSeparator {}
FooterRectangle {
FooterMoreButton {
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/BodyRectangle.qml b/dots/.config/quickshell/ii/modules/waffle/looks/BodyRectangle.qml
similarity index 100%
rename from dots/.config/quickshell/ii/modules/waffle/actionCenter/BodyRectangle.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/BodyRectangle.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/FooterMoreButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/FooterMoreButton.qml
similarity index 100%
rename from dots/.config/quickshell/ii/modules/waffle/actionCenter/FooterMoreButton.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/FooterMoreButton.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/FooterRectangle.qml b/dots/.config/quickshell/ii/modules/waffle/looks/FooterRectangle.qml
similarity index 92%
rename from dots/.config/quickshell/ii/modules/waffle/actionCenter/FooterRectangle.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/FooterRectangle.qml
index e3f7cd120..dcf4f519d 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/FooterRectangle.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/FooterRectangle.qml
@@ -12,6 +12,6 @@ Rectangle {
Layout.fillWidth: true
color: "transparent"
- implicitWidth: 360
+ implicitWidth: 358
implicitHeight: 47
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
index 26ef9f101..0350f5004 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
@@ -20,7 +20,7 @@ Singleton {
property real backgroundTransparency: 0.13
property real panelBackgroundTransparency: 0.12
property real panelLayerTransparency: root.dark ? 0.9 : 0.7
- property real contentTransparency: root.dark ? 0.9 : 0.5
+ property real contentTransparency: root.dark ? 0.87 : 0.5
function applyBackgroundTransparency(col) {
return ColorUtils.applyAlpha(col, 1 - root.backgroundTransparency)
}
@@ -41,8 +41,8 @@ Singleton {
property color bg1Border: '#d7d7d7'
property color bg2: "#FBFBFB"
property color bg2Base: "#FBFBFB"
- property color bg2Hover: "#FDFDFD"
- property color bg2Active: "#FDFDFD"
+ property color bg2Hover: '#ffffff'
+ property color bg2Active: '#eeeeee'
property color bg2Border: '#cdcdcd'
property color subfg: "#5C5C5C"
property color fg: "#000000"
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
index 657897ef1..97ee49d1e 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml
@@ -1,3 +1,4 @@
+pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
@@ -10,11 +11,13 @@ import qs.modules.waffle.looks
Item {
id: root
- signal closed()
+ signal closed
required property Item contentItem
property real visualMargin: 12
property int closeAnimDuration: 150
+ property bool revealFromSides: false
+ property bool revealFromLeft: true
function close() {
closeAnim.start();
@@ -25,16 +28,25 @@ Item {
implicitHeight: contentItem.implicitHeight + visualMargin * 2
implicitWidth: contentItem.implicitWidth + visualMargin * 2
+ focus: true
+ Keys.onPressed: event => { // Esc to close
+ if (event.key === Qt.Key_Escape) {
+ content.close();
+ }
+ }
+
Item {
id: panelContent
anchors {
- left: parent.left
- right: parent.right
- top: root.barAtBottom ? undefined : parent.top
- bottom: root.barAtBottom ? parent.bottom : undefined
+ left: (root.revealFromSides && !root.revealFromLeft) ? undefined : parent.left
+ right: (root.revealFromSides && root.revealFromLeft) ? undefined : parent.right
+ top: (!root.revealFromSides && root.barAtBottom) ? undefined : parent.top
+ bottom: (!root.revealFromSides && !root.barAtBottom) ? undefined : parent.bottom
// Opening anim
- bottomMargin: root.barAtBottom ? sourceEdgeMargin : root.visualMargin
- topMargin: root.barAtBottom ? root.visualMargin : sourceEdgeMargin
+ bottomMargin: (!root.revealFromSides && root.barAtBottom) ? sourceEdgeMargin : root.visualMargin
+ topMargin: (!root.revealFromSides && !root.barAtBottom) ? sourceEdgeMargin : root.visualMargin
+ leftMargin: (root.revealFromSides && root.revealFromLeft) ? sideEdgeMargin : root.visualMargin
+ rightMargin: (root.revealFromSides && !root.revealFromLeft) ? sideEdgeMargin : root.visualMargin
}
Component.onCompleted: {
@@ -42,24 +54,22 @@ Item {
}
property real sourceEdgeMargin: -(implicitHeight + root.visualMargin)
- PropertyAnimation {
+ property real sideEdgeMargin: -(implicitWidth + root.visualMargin)
+ OpenAnim {
id: openAnim
- target: panelContent
- property: "sourceEdgeMargin"
- to: root.visualMargin
- duration: 200
- easing.type: Easing.BezierSpline
- easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
+ properties: "sourceEdgeMargin, sideEdgeMargin"
}
SequentialAnimation {
id: closeAnim
- PropertyAnimation {
- target: panelContent
- property: "sourceEdgeMargin"
- to: -(implicitHeight + root.visualMargin)
- duration: root.closeAnimDuration
- easing.type: Easing.BezierSpline
- easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
+ ParallelAnimation {
+ CloseAnim {
+ property: "sourceEdgeMargin"
+ to: -(implicitHeight + root.visualMargin)
+ }
+ CloseAnim {
+ property: "sideEdgeMargin"
+ to: -(implicitWidth + root.visualMargin)
+ }
}
ScriptAction {
script: {
@@ -70,5 +80,19 @@ Item {
implicitWidth: root.contentItem.implicitWidth
implicitHeight: root.contentItem.implicitHeight
children: [root.contentItem]
- }
+ }
+
+ component OpenAnim: PropertyAnimation {
+ target: panelContent
+ to: root.visualMargin
+ duration: 200
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
+ }
+ component CloseAnim: PropertyAnimation {
+ target: panelContent
+ duration: root.closeAnimDuration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
new file mode 100644
index 000000000..74cb35f8b
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
@@ -0,0 +1,18 @@
+import QtQuick
+import QtQuick.Controls
+import Quickshell
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+WButton {
+ id: root
+
+ colBackground: Looks.colors.bg2
+ colBackgroundHover: Looks.colors.bg2Hover
+ colBackgroundActive: Looks.colors.bg2Active
+ border.color: Looks.colors.bg2Border
+ border.width: root.pressed ? 2 : 1
+
+
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
index 806afcd37..68e836b66 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
@@ -15,8 +15,8 @@ Item {
property alias border: borderRect
property alias borderColor: borderRect.border.color
- implicitWidth: contentItem.implicitWidth
- implicitHeight: contentItem.implicitHeight
+ implicitWidth: borderRect.implicitWidth
+ implicitHeight: borderRect.implicitHeight
WRectangularShadow {
target: borderRect
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/PageColumn.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelPageColumn.qml
similarity index 100%
rename from dots/.config/quickshell/ii/modules/waffle/actionCenter/PageColumn.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/WPanelPageColumn.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/Separator.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelSeparator.qml
similarity index 100%
rename from dots/.config/quickshell/ii/modules/waffle/actionCenter/Separator.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/WPanelSeparator.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
new file mode 100644
index 000000000..79543846b
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
@@ -0,0 +1,51 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+FooterRectangle {
+ id: root
+
+ property bool collapsed
+ implicitWidth: 334
+
+ RowLayout {
+ anchors {
+ fill: parent
+ leftMargin: 16
+ rightMargin: 16
+ topMargin: 12
+ bottomMargin: 12
+ }
+
+ WText {
+ Layout.fillWidth: true
+ font.pixelSize: Looks.font.pixelSize.large
+ text: DateTime.collapsedCalendarFormat
+ }
+
+ WBorderedButton {
+ implicitWidth: 24
+ implicitHeight: 24
+ padding: 0
+ onClicked: root.collapsed = !root.collapsed
+ contentItem: Item {
+ FluentIcon {
+ anchors.centerIn: parent
+ implicitSize: 12
+ icon: "chevron-down"
+ rotation: root.collapsed ? 180 : 0
+ Behavior on rotation {
+ animation: Looks.transition.rotate.createObject(this)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
new file mode 100644
index 000000000..335cecf5a
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
@@ -0,0 +1,23 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+BodyRectangle {
+ id: root
+
+ property bool collapsed
+ implicitHeight: collapsed ? 0 : 400 // For now
+ implicitWidth: 334
+
+ Behavior on implicitHeight {
+ animation: Looks.transition.enter.createObject(this)
+ }
+
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
new file mode 100644
index 000000000..95fc529c2
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
@@ -0,0 +1,87 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+FooterRectangle {
+ Layout.fillWidth: true
+ implicitWidth: 334
+
+ RowLayout {
+ anchors {
+ fill: parent
+ leftMargin: 16
+ rightMargin: 16
+ topMargin: 12
+ bottomMargin: 12
+ }
+ spacing: 0
+
+ SmallBorderedIconButton {
+ visible: !TimerService.pomodoroRunning
+ icon.name: "subtract"
+ onClicked: Config.options.time.pomodoro.focus -= 300 // 5 mins
+ }
+
+ WTextWithFixedWidth {
+ visible: !TimerService.pomodoroRunning
+ implicitWidth: 81
+ horizontalAlignment: Text.AlignHCenter
+ color: Looks.colors.subfg
+ text: Translation.tr("%1 mins").arg(`${TimerService.focusTime / 60}`)
+ }
+
+ SmallBorderedIconButton {
+ visible: !TimerService.pomodoroRunning
+ icon.name: "add"
+ onClicked: Config.options.time.pomodoro.focus += 300 // 5 mins
+ }
+
+ WText {
+ visible: TimerService.pomodoroRunning
+ font.pixelSize: Looks.font.pixelSize.large
+ text: Translation.tr("Focusing")
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ SmallBorderedIconButton {
+ leftPadding: 12
+ rightPadding: 12
+ implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
+
+ onClicked: {
+ if (TimerService.pomodoroRunning) {
+ TimerService.togglePomodoro()
+ TimerService.resetPomodoro()
+ } else {
+ TimerService.togglePomodoro()
+ Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "sidebarRight", "toggle"]);
+ }
+ }
+
+ contentItem: Row {
+ id: focusButtonContent
+ spacing: 4
+ FluentIcon {
+ icon: TimerService.pomodoroRunning ? "stop" : "play"
+ filled: true
+ implicitSize: 14
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ WText {
+ anchors.verticalCenter: parent.verticalCenter
+ text: TimerService.pomodoroRunning ? Translation.tr("End session") : Translation.tr("Focus")
+ }
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
new file mode 100644
index 000000000..44ceef6ba
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -0,0 +1,57 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import Qt.labs.synchronizer
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+WBarAttachedPanelContent {
+ id: root
+
+ readonly property bool barAtBottom: Config.options.waffles.bar.bottom
+ revealFromSides: true
+ revealFromLeft: false
+
+ property bool collapsed: false
+
+ contentItem: Column {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: root.barAtBottom ? undefined : parent.top
+ bottom: root.barAtBottom ? parent.bottom : undefined
+ }
+ spacing: 12
+
+ WPane {
+ contentItem: ColumnLayout {
+ spacing: 0
+ CalendarHeader {
+ Layout.fillWidth: true
+ Synchronizer on collapsed {
+ property alias source: root.collapsed
+ }
+ }
+
+ WPanelSeparator { visible: !root.collapsed }
+
+ CalendarView {
+ Layout.fillWidth: true
+ Synchronizer on collapsed {
+ property alias source: root.collapsed
+ }
+ }
+
+ WPanelSeparator {}
+
+ FocusFooter {
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
new file mode 100644
index 000000000..1236779a7
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
@@ -0,0 +1,18 @@
+import QtQuick
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.waffle.looks
+
+WBorderedButton {
+ id: root
+ implicitWidth: 24
+ implicitHeight: 24
+ contentItem: Item {
+ FluentIcon {
+ anchors.centerIn: parent
+ implicitSize: 12
+ icon: root.icon.name
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WaffleNotificationCenter.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WaffleNotificationCenter.qml
new file mode 100644
index 000000000..4caed7664
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WaffleNotificationCenter.qml
@@ -0,0 +1,85 @@
+import QtQuick
+import Quickshell
+import Quickshell.Io
+import Quickshell.Wayland
+import Quickshell.Hyprland
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+
+Scope {
+ id: root
+
+ Connections {
+ target: GlobalStates
+
+ function onSidebarRightOpenChanged() {
+ if (GlobalStates.sidebarRightOpen) panelLoader.active = true;
+ }
+ }
+
+ Loader {
+ id: panelLoader
+ active: GlobalStates.sidebarRightOpen
+ sourceComponent: PanelWindow {
+ id: panelWindow
+ exclusiveZone: 0
+ WlrLayershell.namespace: "quickshell:wNotificationCenter"
+ WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
+ color: "transparent"
+
+ anchors {
+ bottom: true
+ top: true
+ right: true
+ }
+
+ implicitWidth: content.implicitWidth
+ implicitHeight: content.implicitHeight
+
+ HyprlandFocusGrab {
+ id: focusGrab
+ active: true
+ windows: [panelWindow]
+ onCleared: content.close();
+ }
+
+ Connections {
+ target: GlobalStates
+ function onSidebarRightOpenChanged() {
+ if (!GlobalStates.sidebarRightOpen) content.close();
+ }
+ }
+
+ NotificationCenterContent {
+ id: content
+ anchors.fill: parent
+
+ onClosed: {
+ GlobalStates.sidebarRightOpen = false;
+ panelLoader.active = false;
+ }
+ }
+ }
+ }
+
+ function toggleOpen() {
+ GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
+ }
+
+ IpcHandler {
+ target: "sidebarRight"
+
+ function toggle() {
+ root.toggleOpen();
+ }
+ }
+
+ GlobalShortcut {
+ name: "sidebarRightToggle"
+ description: "Toggles notification center on press"
+
+ onPressed: root.toggleOpen();
+ }
+}
diff --git a/dots/.config/quickshell/ii/services/DateTime.qml b/dots/.config/quickshell/ii/services/DateTime.qml
index 514da212b..e1a8300d4 100644
--- a/dots/.config/quickshell/ii/services/DateTime.qml
+++ b/dots/.config/quickshell/ii/services/DateTime.qml
@@ -22,7 +22,7 @@ Singleton {
property string shortDate: Qt.locale().toString(clock.date, Config.options?.time.shortDateFormat ?? "dd/MM")
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateWithYearFormat ?? "dd/MM/yyyy")
property string longDate: 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, "dddd, MMMM dd")
property string uptime: "0h, 0m"
Timer {
diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml
index b8193812f..6f401c90f 100644
--- a/dots/.config/quickshell/ii/shell.qml
+++ b/dots/.config/quickshell/ii/shell.qml
@@ -31,6 +31,7 @@ import qs.modules.ii.wallpaperSelector
import qs.modules.waffle.actionCenter
import qs.modules.waffle.background
import qs.modules.waffle.bar
+import qs.modules.waffle.notificationCenter
import qs.modules.waffle.onScreenDisplay
import QtQuick
@@ -79,6 +80,7 @@ ShellRoot {
PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} }
PanelLoader { identifier: "wBar"; component: WaffleBar {} }
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
+ PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
ReloadPopup {}
@@ -92,7 +94,7 @@ ShellRoot {
property list families: ["ii", "waffle"]
property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
- "waffle": ["wActionCenter", "wBar", "wBackground", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiSidebarRight", "iiWallpaperSelector"],
+ "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
})
function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily)
From cecb476ed3b164c4d648bf0c56460856c877de4f Mon Sep 17 00:00:00 2001
From: "Celestial.y"
Date: Mon, 24 Nov 2025 23:38:03 +0800
Subject: [PATCH 008/154] Revert the "waybar" note modification
68c159f210b91f75113d454aab6c5866322334f4
---
.github/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/README.md b/.github/README.md
index ff34ca061..b0ad4b9c4 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -50,7 +50,7 @@
| [Quickshell](https://quickshell.outfoxxed.me/) | A QtQuick-based widget system, used for the status bar, sidebars, etc. |
| Others | See [deps-info.md](https://github.com/end-4/dots-hyprland/blob/main/sdata/deps-info.md) |
- **Note: No Waybar here. Please stop calling every bar "Waybar".**
+ _THERE IS NO WAYBAR STOP FUCKING CALLING EVERY BAR WAYBAR_
From 1836a2ff1c7b648bedb433709dc523dcc5f30c84 Mon Sep 17 00:00:00 2001
From: Moeta Yuko
Date: Mon, 24 Nov 2025 12:51:21 +0000
Subject: [PATCH 009/154] brightness: use connector name to distinguish
different monitors
One may have multiple monitors of the same model
---
dots/.config/quickshell/ii/services/Brightness.qml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml
index 465d8729c..7c25f145c 100644
--- a/dots/.config/quickshell/ii/services/Brightness.qml
+++ b/dots/.config/quickshell/ii/services/Brightness.qml
@@ -58,7 +58,7 @@ Singleton {
if (data.startsWith("Display ")) {
const lines = data.split("\n").map(l => l.trim());
root.ddcMonitors.push({
- model: lines.find(l => l.startsWith("Monitor:")).split(":")[2],
+ name: lines.find(l => l.startsWith("DRM connector:")).split("-").slice(1).join('-'),
busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1]
});
}
@@ -76,11 +76,11 @@ Singleton {
required property ShellScreen screen
readonly property bool isDdc: {
- const match = root.ddcMonitors.find(m => m.model === screen.model && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
+ const match = root.ddcMonitors.find(m => m.name === screen.name && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
return !!match;
}
readonly property string busNum: {
- const match = root.ddcMonitors.find(m => m.model === screen.model && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
+ const match = root.ddcMonitors.find(m => m.name === screen.name && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
return match?.busNum ?? "";
}
property int rawMaxBrightness: 100
@@ -215,7 +215,7 @@ Singleton {
Process {
id: screenshotProc
- command: ["bash", "-c",
+ command: ["bash", "-c",
`mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}'`
+ ` && grim -o '${StringUtils.shellSingleQuoteEscape(screenScope.screenName)}' -`
+ ` | magick png:- -colorspace Gray -format "%[fx:mean*100]" info:`
From 5242373db5e35198fe102482dc264fcfd970e89f Mon Sep 17 00:00:00 2001
From: Moeta Yuko
Date: Mon, 24 Nov 2025 18:22:36 +0000
Subject: [PATCH 010/154] brightness: adjust DDCCI initialize timings
* Delay DDCCI monitor initialization until after `ddcutil detect` to
ensure `isDdc`, `busNum`, and `ddcMonitors` are properly set.
* Run `ddcutil getvcp` sequentially to avoid failures from concurrent
executions.
---
.../quickshell/ii/services/Brightness.qml | 36 ++++++++++---------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml
index 7c25f145c..f2f4f0a7e 100644
--- a/dots/.config/quickshell/ii/services/Brightness.qml
+++ b/dots/.config/quickshell/ii/services/Brightness.qml
@@ -48,6 +48,16 @@ Singleton {
ddcProc.running = true;
}
+ function initializeMonitor(i: int): void {
+ if (i >= monitors.length)
+ return;
+ monitors[i].initialize();
+ }
+
+ function ddcDetectFinished(): void {
+ initializeMonitor(0);
+ }
+
Process {
id: ddcProc
@@ -64,7 +74,7 @@ Singleton {
}
}
}
- onExited: root.ddcMonitorsChanged()
+ onExited: root.ddcDetectFinished()
}
Process {
@@ -75,14 +85,8 @@ Singleton {
id: monitor
required property ShellScreen screen
- readonly property bool isDdc: {
- const match = root.ddcMonitors.find(m => m.name === screen.name && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
- return !!match;
- }
- readonly property string busNum: {
- const match = root.ddcMonitors.find(m => m.name === screen.name && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
- return match?.busNum ?? "";
- }
+ property bool isDdc
+ property string busNum
property int rawMaxBrightness: 100
property real brightness
property real brightnessMultiplier: 1.0
@@ -110,6 +114,9 @@ Singleton {
function initialize() {
monitor.ready = false;
+ const match = root.ddcMonitors.find(m => m.name === screen.name && !root.monitors.slice(0, root.monitors.indexOf(this)).some(mon => mon.busNum === m.busNum));
+ isDdc = !!match;
+ busNum = match?.busNum ?? "";
initProc.command = isDdc ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`];
initProc.running = true;
}
@@ -123,6 +130,9 @@ Singleton {
monitor.ready = true;
}
}
+ onExited: (exitCode, exitStatus) => {
+ initializeMonitor(root.monitors.indexOf(monitor) + 1);
+ }
}
// We need a delay for DDC monitors because they can be quite slow and might act weird with rapid changes
@@ -157,14 +167,6 @@ Singleton {
function setBrightnessMultiplier(value: real): void {
monitor.brightnessMultiplier = value;
}
-
- Component.onCompleted: {
- initialize();
- }
-
- onBusNumChanged: {
- initialize();
- }
}
Component {
From 90539274803dc3689bd418c1000ef40baed67efa Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 24 Nov 2025 22:45:54 +0100
Subject: [PATCH 011/154] wnotificationcenter: somewhat working calendar
---
.../waffle/looks/WBorderlessButton.qml | 2 +
.../ii/modules/waffle/looks/WButton.qml | 4 +-
.../notificationCenter/CalendarHeader.qml | 2 +-
.../notificationCenter/CalendarView.qml | 103 +++++++++++++++++-
.../waffle/notificationCenter/FocusFooter.qml | 2 +-
.../NotificationCenterContent.qml | 2 +-
6 files changed, 108 insertions(+), 7 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml
index 0f0d99ad9..7f3546a6b 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml
@@ -25,8 +25,10 @@ Button {
return root.colBackground
}
}
+ property alias radius: background.radius
background: Rectangle {
+ id: background
radius: Looks.radius.medium
color: root.color
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
index 69f255ad9..18fe0244b 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
@@ -23,7 +23,7 @@ Button {
if (root.checked) {
if (root.down) {
return root.colBackgroundToggledActive;
- } else if (root.hovered && !root.down) {
+ } else if (root.hovered) {
return root.colBackgroundToggledHover;
} else {
return root.colBackgroundToggled;
@@ -31,7 +31,7 @@ Button {
}
if (root.down) {
return root.colBackgroundActive;
- } else if (root.hovered && !root.down) {
+ } else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
index 79543846b..3e177f2fa 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
@@ -13,7 +13,7 @@ FooterRectangle {
id: root
property bool collapsed
- implicitWidth: 334
+ implicitWidth: 0
RowLayout {
anchors {
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
index 335cecf5a..07228590c 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
@@ -12,12 +12,111 @@ import qs.modules.waffle.looks
BodyRectangle {
id: root
+ // State
property bool collapsed
- implicitHeight: collapsed ? 0 : 400 // For now
- implicitWidth: 334
+
+ // Sizes
+ property int _rowsPerMonth: 6
+ property real viewHeight: (_rowsPerMonth * buttonSize) + ((_rowsPerMonth - 1) * buttonSpacing)
+ property real buttonSize: 40
+ property real buttonSpacing: 2
+ property real spacePerExtraRow: buttonSize + buttonSpacing
+
+ implicitWidth: currentMonthGrid.implicitWidth
+ implicitHeight: collapsed ? 0 : viewHeight
+ opacity: implicitHeight > 0 ? 1 : 0
Behavior on implicitHeight {
animation: Looks.transition.enter.createObject(this)
}
+ // Month stuff
+ property real targetMonthDiff: 0
+ property real monthDiff: targetMonthDiff
+ property int focusedMonthDiff: monthDiff // whole part of monthDiff
+ property int currentMonth: DateTime.clock.date.getMonth() + 1 // 0-indexed -> 1-indexed
+ property int currentYear: DateTime.clock.date.getFullYear()
+
+ clip: true
+ property list monthGrids: [previousPreviousMonthGrid, previousMonthGrid, currentMonthGrid, nextMonthGrid, nextNextMonthGrid]
+ ColumnLayout {
+ spacing: 0
+ y: {
+ const origin = - currentMonthGrid.y;
+ const diff = root.monthDiff * root.viewHeight;
+ return origin + (-diff % root.viewHeight);
+ }
+ DiffMonthGrid {
+ id: previousPreviousMonthGrid
+ monthDiff: root.focusedMonthDiff - 2
+ }
+ DiffMonthGrid {
+ id: previousMonthGrid
+ monthDiff: root.focusedMonthDiff - 1
+ }
+ DiffMonthGrid {
+ id: currentMonthGrid
+ monthDiff: root.focusedMonthDiff
+ }
+ DiffMonthGrid {
+ id: nextMonthGrid
+ monthDiff: root.focusedMonthDiff + 1
+ }
+ DiffMonthGrid {
+ id: nextNextMonthGrid
+ monthDiff: root.focusedMonthDiff + 2
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onWheel: wheel => {
+ root.targetMonthDiff += wheel.angleDelta.y / 120 * -0.333333; // Reverse cuz scrolling down should advance
+ }
+ }
+
+ Behavior on monthDiff {
+ animation: Looks.transition.enter.createObject(this)
+ }
+
+ component DiffMonthGrid: MonthGrid {
+ id: monthGrid
+ required property int monthDiff
+ property int index: root.monthGrids.indexOf(this)
+ month: ((root.currentMonth - 1) + monthDiff) % 12 // 1-indexed -> 0-indexed
+ year: root.currentYear + Math.floor((root.currentMonth - 1 + monthDiff) / 12)
+
+ spacing: root.buttonSpacing
+ // background: Rectangle {
+ // color: Qt.rgba(Math.abs(Math.sin(month * 12.9898)) % 1, Math.abs(Math.sin(month * 78.233)) % 1, Math.abs(Math.sin(month * 45.164)) % 1, 1)
+ // }
+ delegate: MonthDayButton {}
+ }
+
+ component MonthDayButton: WButton {
+ id: monthDayButton
+ required property var model
+ opacity: model.month == parent.parent.month || model.today ? 1 : 0
+ checked: model.today
+ implicitWidth: root.buttonSize
+ implicitHeight: root.buttonSize
+ radius: height / 2
+
+ required property int index
+
+ contentItem: Item {
+ WText {
+ anchors.centerIn: parent
+ text: monthDayButton.model.day
+ color: {
+ if (monthDayButton.model.today)
+ return Looks.colors.accentFg;
+ if (monthDayButton.model.month == root.currentMonth - 1)
+ return Looks.colors.fg;
+ return Looks.colors.subfg;
+ }
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+ }
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
index 95fc529c2..c66925d04 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
@@ -11,7 +11,7 @@ import qs.modules.waffle.looks
FooterRectangle {
Layout.fillWidth: true
- implicitWidth: 334
+ implicitWidth: 0
RowLayout {
anchors {
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
index 44ceef6ba..c2b97f6dc 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -40,7 +40,7 @@ WBarAttachedPanelContent {
WPanelSeparator { visible: !root.collapsed }
CalendarView {
- Layout.fillWidth: true
+ // Layout.fillWidth: true
Synchronizer on collapsed {
property alias source: root.collapsed
}
From 08739043f68f8d4bde6fafe4e89adf92366b195e Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Tue, 25 Nov 2025 10:44:29 +0100
Subject: [PATCH 012/154] right sidebar: don't load all bottom group tabs
---
.../ii/sidebarRight/BottomWidgetGroup.qml | 119 ++++------
.../modules/ii/sidebarRight/todo/TaskList.qml | 217 +++++++-----------
.../notificationCenter/CalendarView.qml | 2 +
3 files changed, 137 insertions(+), 201 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
index f81e9db13..2adb5f503 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
@@ -16,9 +16,9 @@ Rectangle {
property int selectedTab: Persistent.states.sidebar.bottomGroup.tab
property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed
property var tabs: [
- {"type": "calendar", "name": Translation.tr("Calendar"), "icon": "calendar_month", "widget": calendarWidget},
- {"type": "todo", "name": Translation.tr("To Do"), "icon": "done_outline", "widget": todoWidget},
- {"type": "timer", "name": Translation.tr("Timer"), "icon": "schedule", "widget": pomodoroWidget},
+ {"type": "calendar", "name": Translation.tr("Calendar"), "icon": "calendar_month", "widget": "calendar/CalendarWidget.qml"},
+ {"type": "todo", "name": Translation.tr("To Do"), "icon": "done_outline", "widget": "todo/TodoWidget.qml"},
+ {"type": "timer", "name": Translation.tr("Timer"), "icon": "schedule", "widget": "pomodoro/PomodoroWidget.qml"},
]
Behavior on implicitHeight {
@@ -170,83 +170,56 @@ Rectangle {
}
// Content area
- StackLayout {
+ Loader {
id: tabStack
Layout.fillWidth: true
- // Take the highest one, because the TODO list has no implicit height. This way the heigth of the calendar is used when it's initially loaded with the TODO list
- height: Math.max(...tabStack.children.map(child => child.tabLoader?.implicitHeight || 0)) // TODO: make this less stupid
- Layout.alignment: Qt.AlignVCenter
- property int realIndex: root.selectedTab
- property int animationDuration: Appearance.animation.elementMoveFast.duration * 1.5
- currentIndex: root.selectedTab
+ Layout.fillHeight: true
+ source: root.tabs[root.selectedTab].widget
- // Switch the tab on halfway of the anim duration
- Connections {
- target: root
- function onSelectedTabChanged() {
- delayedStackSwitch.start()
- tabStack.realIndex = root.selectedTab
- }
- }
- Timer {
- id: delayedStackSwitch
- interval: tabStack.animationDuration / 2
- repeat: false
- onTriggered: {
- tabStack.currentIndex = root.selectedTab
- }
- }
+ Behavior on source {
+ id: switchBehavior
- Repeater {
- model: tabs
- Item { // TODO: make behavior on y also act for the item that's switched to
- id: tabItem
- property int tabIndex: index
- property string tabType: modelData.type
- property int animDistance: 5
- property var tabLoader: tabLoader
- // Opacity: show up only when being animated to
- opacity: (tabStack.currentIndex === tabItem.tabIndex && tabStack.realIndex === tabItem.tabIndex) ? 1 : 0
- // Y: starts animating when user selects a different tab
- y: (tabStack.realIndex === tabItem.tabIndex) ? 0 : (tabStack.realIndex < tabItem.tabIndex) ? animDistance : -animDistance
- Behavior on opacity { NumberAnimation { duration: tabStack.animationDuration / 2; easing.type: Easing.OutCubic } }
- Behavior on y { NumberAnimation { duration: tabStack.animationDuration; easing.type: Easing.OutExpo } }
- Loader {
- id: tabLoader
- anchors.fill: parent
- sourceComponent: modelData.widget
- focus: root.selectedTab === tabItem.tabIndex
+ SequentialAnimation {
+ id: switchAnim
+ ParallelAnimation {
+ PropertyAnimation {
+ target: tabStack.item
+ properties: "opacity"
+ to: 0
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
+ }
+ PropertyAnimation {
+ target: tabStack.item
+ properties: "y"
+ from: 0
+ to: 20
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.InExpo
+ }
+ }
+ PropertyAction {} // The source change happens here
+ ParallelAnimation {
+ PropertyAnimation {
+ target: tabStack.item
+ properties: "opacity"
+ to: 1
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
+ }
+ PropertyAnimation {
+ target: tabStack.item
+ properties: "y"
+ from: 20
+ to: 0
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.OutExpo
+ }
}
}
}
}
}
-
- // Calendar component
- Component {
- id: calendarWidget
-
- CalendarWidget {
- anchors.fill: parent
- anchors.margins: 5
- }
- }
-
- // To Do component
- Component {
- id: todoWidget
- TodoWidget {
- anchors.fill: parent
- anchors.margins: 5
- }
- }
-
- // Pomodoro component
- Component {
- id: pomodoroWidget
- PomodoroWidget {
- anchors.fill: parent
- anchors.margins: 5
- }
- }
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/todo/TaskList.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/todo/TaskList.qml
index 4f6a4304d..b48352f31 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/todo/TaskList.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/todo/TaskList.qml
@@ -9,147 +9,108 @@ import Quickshell
Item {
id: root
- required property var taskList;
+ required property var taskList
property string emptyPlaceholderIcon
property string emptyPlaceholderText
property int todoListItemSpacing: 5
property int todoListItemPadding: 8
property int listBottomPadding: 80
- StyledFlickable {
- id: flickable
+ StyledListView {
+ id: listView
anchors.fill: parent
- contentHeight: columnLayout.height
-
- clip: true
- layer.enabled: true
- layer.effect: OpacityMask {
- maskSource: Rectangle {
- width: flickable.width
- height: flickable.height
- radius: Appearance.rounding.small
- }
+ spacing: root.todoListItemSpacing
+ animateAppearance: false
+ model: ScriptModel {
+ values: root.taskList
}
+ delegate: Item {
+ id: todoItem
+ required property var modelData
+ property bool pendingDoneToggle: false
+ property bool pendingDelete: false
+ property bool enableHeightAnimation: false
- ColumnLayout {
- id: columnLayout
- width: parent.width
- spacing: 0
- Repeater {
- model: ScriptModel {
- values: taskList
+ implicitHeight: todoItemRectangle.implicitHeight
+ width: ListView.view.width
+ clip: true
+
+ Behavior on implicitHeight {
+ enabled: enableHeightAnimation
+ NumberAnimation {
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Appearance.animation.elementMoveFast.type
+ easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
- delegate: Item {
- id: todoItem
- property bool pendingDoneToggle: false
- property bool pendingDelete: false
- property bool enableHeightAnimation: false
-
- Layout.fillWidth: true
- implicitHeight: todoItemRectangle.implicitHeight + todoListItemSpacing
- height: implicitHeight
- clip: true
-
- Behavior on implicitHeight {
- enabled: enableHeightAnimation
- NumberAnimation {
- duration: Appearance.animation.elementMoveFast.duration
- easing.type: Appearance.animation.elementMoveFast.type
- easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
- }
- }
-
- function startAction() {
- enableHeightAnimation = true
- todoItem.implicitHeight = 0
- actionTimer.start()
- }
-
- Timer {
- id: actionTimer
- interval: Appearance.animation.elementMoveFast.duration
- repeat: false
- onTriggered: {
- if (todoItem.pendingDelete) {
- Todo.deleteItem(modelData.originalIndex)
- } else if (todoItem.pendingDoneToggle) {
- if (!modelData.done) Todo.markDone(modelData.originalIndex)
- else Todo.markUnfinished(modelData.originalIndex)
- }
- }
- }
-
- Rectangle {
- id: todoItemRectangle
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- implicitHeight: todoContentRowLayout.implicitHeight
- color: Appearance.colors.colLayer2
- radius: Appearance.rounding.small
- ColumnLayout {
- id: todoContentRowLayout
- anchors.left: parent.left
- anchors.right: parent.right
-
- StyledText {
- Layout.fillWidth: true // Needed for wrapping
- Layout.leftMargin: 10
- Layout.rightMargin: 10
- Layout.topMargin: todoListItemPadding
- id: todoContentText
- text: modelData.content
- wrapMode: Text.Wrap
- }
- RowLayout {
- Layout.leftMargin: 10
- Layout.rightMargin: 10
- Layout.bottomMargin: todoListItemPadding
- Item {
- Layout.fillWidth: true
- }
- TodoItemActionButton {
- Layout.fillWidth: false
- onClicked: {
- todoItem.pendingDoneToggle = true
- todoItem.startAction()
- }
- contentItem: MaterialSymbol {
- anchors.centerIn: parent
- horizontalAlignment: Text.AlignHCenter
- text: modelData.done ? "remove_done" : "check"
- iconSize: Appearance.font.pixelSize.larger
- color: Appearance.colors.colOnLayer1
- }
- }
- TodoItemActionButton {
- Layout.fillWidth: false
- onClicked: {
- todoItem.pendingDelete = true
- todoItem.startAction()
- }
- contentItem: MaterialSymbol {
- anchors.centerIn: parent
- horizontalAlignment: Text.AlignHCenter
- text: "delete_forever"
- iconSize: Appearance.font.pixelSize.larger
- color: Appearance.colors.colOnLayer1
- }
- }
- }
- }
- }
- }
-
}
- // Bottom padding
- Item {
- implicitHeight: listBottomPadding
+
+ Rectangle {
+ id: todoItemRectangle
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ implicitHeight: todoContentRowLayout.implicitHeight
+ color: Appearance.colors.colLayer2
+ radius: Appearance.rounding.small
+
+ ColumnLayout {
+ id: todoContentRowLayout
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ StyledText {
+ id: todoContentText
+ Layout.fillWidth: true // Needed for wrapping
+ Layout.leftMargin: 10
+ Layout.rightMargin: 10
+ Layout.topMargin: todoListItemPadding
+ text: todoItem.modelData.content
+ wrapMode: Text.Wrap
+ }
+ RowLayout {
+ Layout.leftMargin: 10
+ Layout.rightMargin: 10
+ Layout.bottomMargin: todoListItemPadding
+ Item {
+ Layout.fillWidth: true
+ }
+ TodoItemActionButton {
+ Layout.fillWidth: false
+ onClicked: {
+ if (!todoItem.modelData.done)
+ Todo.markDone(todoItem.modelData.originalIndex);
+ else
+ Todo.markUnfinished(todoItem.modelData.originalIndex);
+ }
+ contentItem: MaterialSymbol {
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: todoItem.modelData.done ? "remove_done" : "check"
+ iconSize: Appearance.font.pixelSize.larger
+ color: Appearance.colors.colOnLayer1
+ }
+ }
+ TodoItemActionButton {
+ Layout.fillWidth: false
+ onClicked: {
+ Todo.deleteItem(todoItem.modelData.originalIndex);
+ }
+ contentItem: MaterialSymbol {
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: "delete_forever"
+ iconSize: Appearance.font.pixelSize.larger
+ color: Appearance.colors.colOnLayer1
+ }
+ }
+ }
+ }
}
}
}
-
- Item { // Placeholder when list is empty
+
+ Item {
+ // Placeholder when list is empty
visible: opacity > 0
opacity: taskList.length === 0 ? 1 : 0
anchors.fill: parent
@@ -177,4 +138,4 @@ Item {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
index 07228590c..b0ff57684 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
@@ -9,6 +9,8 @@ import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
+// TODO: The overlaps are crazy, but the positioning approach works.
+// This could work well if we do it week by week instead of month by month.
BodyRectangle {
id: root
From b4920a7cb610c026ec8683f73909400f39097340 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Tue, 25 Nov 2025 13:12:46 +0100
Subject: [PATCH 013/154] right sidebar: slightly nicer bottom group tab switch
anim
---
.../ii/sidebarRight/BottomWidgetGroup.qml | 197 ++++++++++++------
1 file changed, 128 insertions(+), 69 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
index 2adb5f503..638e2d56f 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
@@ -1,3 +1,4 @@
+pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import qs.services
@@ -12,32 +13,47 @@ Rectangle {
radius: Appearance.rounding.normal
color: Appearance.colors.colLayer1
clip: true
- implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight
+ implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : 350
property int selectedTab: Persistent.states.sidebar.bottomGroup.tab
+ property int previousIndex: -1
property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed
property var tabs: [
- {"type": "calendar", "name": Translation.tr("Calendar"), "icon": "calendar_month", "widget": "calendar/CalendarWidget.qml"},
- {"type": "todo", "name": Translation.tr("To Do"), "icon": "done_outline", "widget": "todo/TodoWidget.qml"},
- {"type": "timer", "name": Translation.tr("Timer"), "icon": "schedule", "widget": "pomodoro/PomodoroWidget.qml"},
+ {
+ "type": "calendar",
+ "name": Translation.tr("Calendar"),
+ "icon": "calendar_month",
+ "widget": "calendar/CalendarWidget.qml"
+ },
+ {
+ "type": "todo",
+ "name": Translation.tr("To Do"),
+ "icon": "done_outline",
+ "widget": "todo/TodoWidget.qml"
+ },
+ {
+ "type": "timer",
+ "name": Translation.tr("Timer"),
+ "icon": "schedule",
+ "widget": "pomodoro/PomodoroWidget.qml"
+ },
]
Behavior on implicitHeight {
NumberAnimation {
duration: Appearance.animation.elementMove.duration
easing.type: Appearance.animation.elementMove.type
- easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
+ easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
}
}
function setCollapsed(state) {
- Persistent.states.sidebar.bottomGroup.collapsed = state
+ Persistent.states.sidebar.bottomGroup.collapsed = state;
if (collapsed) {
- bottomWidgetGroupRow.opacity = 0
+ bottomWidgetGroupRow.opacity = 0;
+ } else {
+ collapsedBottomWidgetGroupRow.opacity = 0;
}
- else {
- collapsedBottomWidgetGroupRow.opacity = 0
- }
- collapseCleanFadeTimer.start()
+ collapseCleanFadeTimer.start();
}
Timer {
@@ -45,18 +61,19 @@ Rectangle {
interval: Appearance.animation.elementMove.duration / 2
repeat: false
onTriggered: {
- if(collapsed) collapsedBottomWidgetGroupRow.opacity = 1
- else bottomWidgetGroupRow.opacity = 1
+ if (collapsed)
+ collapsedBottomWidgetGroupRow.opacity = 1;
+ else
+ bottomWidgetGroupRow.opacity = 1;
}
}
- Keys.onPressed: (event) => {
- if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp)
- && event.modifiers === Qt.ControlModifier) {
+ Keys.onPressed: event => {
+ if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) && event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_PageDown) {
- root.selectedTab = Math.min(root.selectedTab + 1, root.tabs.length - 1)
+ root.selectedTab = Math.min(root.selectedTab + 1, root.tabs.length - 1);
} else if (event.key === Qt.Key_PageUp) {
- root.selectedTab = Math.max(root.selectedTab - 1, 0)
+ root.selectedTab = Math.max(root.selectedTab - 1, 0);
}
event.accepted = true;
}
@@ -77,13 +94,13 @@ Rectangle {
}
spacing: 15
-
+
CalendarHeaderButton {
Layout.margins: 10
Layout.rightMargin: 0
forceCircle: true
downAction: () => {
- root.setCollapsed(false)
+ root.setCollapsed(false);
}
contentItem: MaterialSymbol {
text: "keyboard_arrow_up"
@@ -94,7 +111,7 @@ Rectangle {
}
StyledText {
- property int remainingTasks: Todo.list.filter(task => !task.done).length;
+ property int remainingTasks: Todo.list.filter(task => !task.done).length
Layout.margins: 10
Layout.leftMargin: 0
// text: `${DateTime.collapsedCalendarFormat} • ${remainingTasks} task${remainingTasks > 1 ? "s" : ""}`
@@ -119,10 +136,10 @@ Rectangle {
}
}
- anchors.fill: parent
- height: tabStack.height
+ anchors.fill: parent
+ // implicitHeight: tabStack.implicitHeight
spacing: 10
-
+
// Navigation rail
Item {
Layout.fillHeight: true
@@ -141,13 +158,15 @@ Rectangle {
Repeater {
model: root.tabs
NavigationRailButton {
+ required property int index
+ required property var modelData
showToggledHighlight: false
toggled: root.selectedTab == index
buttonText: modelData.name
buttonIcon: modelData.icon
onPressed: {
- root.selectedTab = index
- Persistent.states.sidebar.bottomGroup.tab = index
+ root.selectedTab = index;
+ Persistent.states.sidebar.bottomGroup.tab = index;
}
}
}
@@ -158,7 +177,7 @@ Rectangle {
anchors.top: parent.top
forceCircle: true
downAction: () => {
- root.setCollapsed(true)
+ root.setCollapsed(true);
}
contentItem: MaterialSymbol {
text: "keyboard_arrow_down"
@@ -170,56 +189,96 @@ Rectangle {
}
// Content area
- Loader {
- id: tabStack
+ Item {
Layout.fillWidth: true
Layout.fillHeight: true
- source: root.tabs[root.selectedTab].widget
+ // implicitHeight: tabStack.implicitHeight
- Behavior on source {
- id: switchBehavior
+ Loader {
+ id: tabStack
+ anchors.fill: parent
+ anchors.bottomMargin: -anchors.topMargin
- SequentialAnimation {
- id: switchAnim
- ParallelAnimation {
- PropertyAnimation {
- target: tabStack.item
- properties: "opacity"
- to: 0
- duration: Appearance.animation.elementMoveFast.duration
- easing.type: Easing.BezierSpline
- easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
- }
- PropertyAnimation {
- target: tabStack.item
- properties: "y"
- from: 0
- to: 20
- duration: Appearance.animation.elementMoveFast.duration
- easing.type: Easing.InExpo
- }
+ Component.onCompleted: {
+ tabStack.source = root.tabs[root.selectedTab].widget;
+ }
+
+ Connections {
+ target: root
+ function onSelectedTabChanged() {
+ if (root.currentTab > root.previousIndex)
+ tabSwitchBehavior.animation.down = true;
+ else if (root.currentTab < root.previousIndex)
+ tabSwitchBehavior.animation.down = false;
+ tabStack.source = root.tabs[root.selectedTab].widget;
}
- PropertyAction {} // The source change happens here
- ParallelAnimation {
- PropertyAnimation {
- target: tabStack.item
- properties: "opacity"
- to: 1
- duration: Appearance.animation.elementMoveFast.duration
- easing.type: Easing.BezierSpline
- easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
- }
- PropertyAnimation {
- target: tabStack.item
- properties: "y"
- from: 20
- to: 0
- duration: Appearance.animation.elementMoveFast.duration
- easing.type: Easing.OutExpo
- }
+ }
+
+ Behavior on source {
+ id: tabSwitchBehavior
+ animation: TabSwitchAnim {
+ id: upAnim
+ down: true
}
}
}
}
}
+
+ component TabSwitchAnim: SequentialAnimation {
+ id: switchAnim
+ property bool down: false
+ // ScriptAction {
+ // script: {
+ // switchAnim.down = root.selectedTab > root.previousIndex;
+ // }
+ // }
+ ParallelAnimation {
+ PropertyAnimation {
+ target: tabStack
+ properties: "opacity"
+ to: 0
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
+ }
+ PropertyAnimation {
+ target: tabStack.anchors
+ properties: "topMargin"
+ to: 10 * (switchAnim.down ? -1 : 1)
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
+ }
+ }
+ PropertyAction {
+ target: tabStack
+ property: "source"
+ value: root.tabs[root.selectedTab].widget
+ } // The source change happens here
+ ParallelAnimation {
+ PropertyAnimation {
+ target: tabStack.anchors
+ properties: "topMargin"
+ from: 10 * -(switchAnim.down ? -1 : 1)
+ to: 0
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveEnter.bezierCurve
+ }
+ PropertyAnimation {
+ target: tabStack
+ properties: "opacity"
+ to: 1
+ duration: Appearance.animation.elementMoveFast.duration
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.animation.elementMoveEnter.bezierCurve
+ }
+ }
+ ScriptAction {
+ script: {
+ root.previousIndex = root.selectedTab;
+ }
+ }
+ }
}
From e4b5718833eb891f1a7a6b74f997bbfe365303ba Mon Sep 17 00:00:00 2001
From: wooze-pao
Date: Tue, 25 Nov 2025 23:08:31 -0600
Subject: [PATCH 014/154] Fix: finger print keep running when use password
login
---
dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml
index b242cdc05..753044afa 100644
--- a/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml
+++ b/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml
@@ -70,7 +70,7 @@ Scope {
}
function stopFingerPam() {
- if (fingerPam.running) {
+ if (fingerPam.active) {
fingerPam.abort();
}
}
From 9ba8723a5dfe51c364042fa20130cac9483683d3 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Wed, 26 Nov 2025 19:40:19 +0100
Subject: [PATCH 015/154] waffles: map media controls bind to action center
---
.../ii/sidebarRight/BottomWidgetGroup.qml | 5 ----
.../sidebarRight/calendar/calendar_layout.js | 6 ++---
.../actionCenter/WaffleActionCenter.qml | 27 ++++++++++++++++---
dots/.config/quickshell/ii/shell.qml | 2 +-
4 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
index 638e2d56f..4c6ea6dd9 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml
@@ -228,11 +228,6 @@ Rectangle {
component TabSwitchAnim: SequentialAnimation {
id: switchAnim
property bool down: false
- // ScriptAction {
- // script: {
- // switchAnim.down = root.selectedTab > root.previousIndex;
- // }
- // }
ParallelAnimation {
PropertyAnimation {
target: tabStack
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/calendar/calendar_layout.js b/dots/.config/quickshell/ii/modules/ii/sidebarRight/calendar/calendar_layout.js
index 7f750b411..e2042bff7 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/calendar/calendar_layout.js
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/calendar/calendar_layout.js
@@ -74,7 +74,7 @@ function getCalendarLayout(dateObject, highlight) {
// Fill
var monthDiff = (weekdayOfMonthFirst == 0 ? 0 : -1);
var toFill, dim;
- if(weekdayOfMonthFirst == 0) {
+ if (weekdayOfMonthFirst == 0) {
toFill = 1;
dim = daysInMonth;
}
@@ -88,8 +88,7 @@ function getCalendarLayout(dateObject, highlight) {
calendar[i][j] = {
"day": toFill,
"today": ((toFill == day && monthDiff == 0 && highlight) ? 1 : (
- monthDiff == 0 ? 0 :
- -1
+ monthDiff == 0 ? 0 : -1
))
};
// Increment
@@ -112,4 +111,3 @@ function getCalendarLayout(dateObject, highlight) {
}
return calendar;
}
-
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
index 56fbedda3..48e81bbc2 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml
@@ -15,7 +15,8 @@ Scope {
target: GlobalStates
function onSidebarLeftOpenChanged() {
- if (GlobalStates.sidebarLeftOpen) panelLoader.active = true;
+ if (GlobalStates.sidebarLeftOpen)
+ panelLoader.active = true;
}
}
@@ -42,13 +43,14 @@ Scope {
id: focusGrab
active: true
windows: [panelWindow]
- onCleared: content.close();
+ onCleared: content.close()
}
Connections {
target: GlobalStates
function onSidebarLeftOpenChanged() {
- if (!GlobalStates.sidebarLeftOpen) content.close();
+ if (!GlobalStates.sidebarLeftOpen)
+ content.close();
}
}
@@ -80,6 +82,23 @@ Scope {
name: "sidebarLeftToggle"
description: "Toggles left sidebar on press"
- onPressed: root.toggleOpen();
+ onPressed: root.toggleOpen()
+ }
+
+ IpcHandler {
+ target: "mediaControls"
+
+ function toggle(): void {
+ GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
+ }
+ }
+
+ GlobalShortcut {
+ name: "mediaControlsToggle"
+ description: "Toggles media controls on press"
+
+ onPressed: {
+ GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
+ }
}
}
diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml
index 6f401c90f..3f57c0c28 100644
--- a/dots/.config/quickshell/ii/shell.qml
+++ b/dots/.config/quickshell/ii/shell.qml
@@ -94,7 +94,7 @@ ShellRoot {
property list families: ["ii", "waffle"]
property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
- "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
+ "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
})
function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily)
From a786f0353ebf4a9c9395bd25b5e70aa27f3fc02b Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Wed, 26 Nov 2025 22:55:09 +0100
Subject: [PATCH 016/154] listview anims always run to end
---
.../quickshell/ii/modules/common/Appearance.qml | 17 +++++++++++------
.../modules/common/widgets/StyledListView.qml | 1 +
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/Appearance.qml b/dots/.config/quickshell/ii/modules/common/Appearance.qml
index d528e6bd5..9c5045014 100644
--- a/dots/.config/quickshell/ii/modules/common/Appearance.qml
+++ b/dots/.config/quickshell/ii/modules/common/Appearance.qml
@@ -278,6 +278,7 @@ Singleton {
property int velocity: 650
property Component numberAnimation: Component {
NumberAnimation {
+ alwaysRunToEnd: true
duration: root.animation.elementMoveEnter.duration
easing.type: root.animation.elementMoveEnter.type
easing.bezierCurve: root.animation.elementMoveEnter.bezierCurve
@@ -292,6 +293,7 @@ Singleton {
property int velocity: 650
property Component numberAnimation: Component {
NumberAnimation {
+ alwaysRunToEnd: true
duration: root.animation.elementMoveExit.duration
easing.type: root.animation.elementMoveExit.type
easing.bezierCurve: root.animation.elementMoveExit.bezierCurve
@@ -310,9 +312,10 @@ Singleton {
easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}}
property Component numberAnimation: Component { NumberAnimation {
- duration: root.animation.elementMoveFast.duration
- easing.type: root.animation.elementMoveFast.type
- easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
+ alwaysRunToEnd: true
+ duration: root.animation.elementMoveFast.duration
+ easing.type: root.animation.elementMoveFast.type
+ easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}}
}
@@ -323,6 +326,7 @@ Singleton {
property int velocity: 650
property Component numberAnimation: Component {
NumberAnimation {
+ alwaysRunToEnd: true
duration: root.animation.elementResize.duration
easing.type: root.animation.elementResize.type
easing.bezierCurve: root.animation.elementResize.bezierCurve
@@ -336,9 +340,10 @@ Singleton {
property list bezierCurve: animationCurves.expressiveDefaultSpatial
property int velocity: 850
property Component numberAnimation: Component { NumberAnimation {
- duration: root.animation.clickBounce.duration
- easing.type: root.animation.clickBounce.type
- easing.bezierCurve: root.animation.clickBounce.bezierCurve
+ alwaysRunToEnd: true
+ duration: root.animation.clickBounce.duration
+ easing.type: root.animation.clickBounce.type
+ easing.bezierCurve: root.animation.clickBounce.bezierCurve
}}
}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml
index 2db1f094a..26518cfb1 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml
@@ -54,6 +54,7 @@ ListView {
Behavior on contentY {
NumberAnimation {
id: scrollAnim
+ alwaysRunToEnd: true
duration: Appearance.animation.scroll.duration
easing.type: Appearance.animation.scroll.type
easing.bezierCurve: Appearance.animation.scroll.bezierCurve
From d27fbede2ac9f02d5ae4b8daf3806d37f069df78 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Wed, 26 Nov 2025 22:57:40 +0100
Subject: [PATCH 017/154] waffles: more continuous infinite scrolling calendar
---
.../ii/modules/common/functions/DateUtils.qml | 38 +++++
.../modules/common/widgets/CalendarView.qml | 118 ++++++++++++++++
.../ii/modules/common/widgets/WeekRow.qml | 43 ++++++
.../ii/modules/waffle/looks/Looks.qml | 8 ++
.../ii/modules/waffle/looks/WButton.qml | 7 +-
.../notificationCenter/CalendarView.qml | 124 ----------------
.../notificationCenter/CalendarWidget.qml | 132 ++++++++++++++++++
.../{CalendarHeader.qml => DateHeader.qml} | 6 +-
.../waffle/notificationCenter/FocusFooter.qml | 1 +
.../NotificationCenterContent.qml | 6 +-
10 files changed, 354 insertions(+), 129 deletions(-)
create mode 100644 dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
delete mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
rename dots/.config/quickshell/ii/modules/waffle/notificationCenter/{CalendarHeader.qml => DateHeader.qml} (87%)
diff --git a/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml b/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
new file mode 100644
index 000000000..a7527bcb8
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
@@ -0,0 +1,38 @@
+pragma Singleton
+import Quickshell
+
+Singleton {
+ id: root
+
+ function getMonday(date, american = false) {
+ const d = new Date(date); // Copy
+ const day = d.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
+
+ // Calculate difference to Monday
+ if (american) {
+ // Week starts on Sunday
+ d.setDate(d.getDate() - day);
+ } else {
+ // Week starts on Monday
+ const diff = day === 0 ? -6 : 1 - day;
+ d.setDate(d.getDate() + diff);
+ }
+
+ return d;
+ }
+
+ function sameDate(d1, d2) {
+ return (
+ d1.getFullYear() === d2.getFullYear() &&
+ d1.getMonth() === d2.getMonth() &&
+ d1.getDate() === d2.getDate()
+ );
+ }
+
+ function getIthDayDateOfSameWeek(date, i, american = false) {
+ const monday = root.getMonday(date, american);
+ const targetDate = new Date(monday);
+ targetDate.setDate(monday.getDate() + i);
+ return targetDate;
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
new file mode 100644
index 000000000..56997ecba
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
@@ -0,0 +1,118 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+Item {
+ id: root
+
+ // Expose delegate
+ property Component delegate: Text {
+ required property var model
+ text: model.day
+ }
+
+ // Configuration
+ property int paddingWeeks: 2 // 1 should be sufficient with proper clipping and no padding
+ property bool american: false // 🍔🦅 = Sunday first
+
+ // Scrolling
+ function scrollMonthsAndSnap(x) { // Scroll x months and snap to month
+ const focusedDate = root.focusedDate;
+ const focusedMonth = focusedDate.getMonth();
+ const focusedYear = focusedDate.getFullYear();
+ const targetMonth = focusedMonth + x;
+ const targetDate = new Date(focusedYear, targetMonth, 1);
+ const currentFirstShownDate = new Date(root.dateInFirstWeek.getTime() + (root.paddingWeeks * root.millisPerWeek));
+ const diffMillis = targetDate.getTime() - currentFirstShownDate.getTime();
+ const diffWeeks = Math.round(diffMillis / root.millisPerWeek);
+ root.targetWeekDiff += diffWeeks;
+ }
+ property int weeksPerScroll: 1
+ property real targetWeekDiff: 0
+ property real weekDiff: targetWeekDiff
+ property int contentWeekDiff: weekDiff // whole part of weekDiff
+ property bool scrolling: false
+
+ Behavior on weekDiff {
+ id: weekScrollBehavior
+ animation: Looks.transition.scroll.createObject(this)
+ }
+ Timer {
+ id: scrollAnimationCheckTimer
+ interval: 30 // Should be plenty for 60fps
+ onTriggered: root.scrolling = false;
+ }
+ onWeekDiffChanged: {
+ scrolling = true;
+ scrollAnimationCheckTimer.restart();
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onWheel: wheel => {
+ root.targetWeekDiff += wheel.angleDelta.y / 120 * -root.weeksPerScroll; // Reverse cuz scrolling down should advance
+ }
+ }
+
+ // Date calculations
+ readonly property int millisPerWeek: 7 * 24 * 60 * 60 * 1000
+ readonly property int totalWeeks: 6 + (paddingWeeks * 2)
+ readonly property int focusedWeekIndex: 2 // The third row, 0-indexed
+ readonly property int focusDayOfWeekIndex: 6 // Non-American
+ property date dateInFirstWeek: {
+ const currentDate = new Date();
+ const currentMonth = currentDate.getMonth();
+ const currentYear = currentDate.getFullYear();
+ const firstDayThisMonth = new Date(currentYear, currentMonth, 1);
+ return new Date(firstDayThisMonth.getTime() - (paddingWeeks * millisPerWeek) + contentWeekDiff * millisPerWeek);
+ }
+ property date focusedDate: {
+ // The last day of 3rd week shown is considered the focused month
+ const addedTime = (root.paddingWeeks + root.focusedWeekIndex) * root.millisPerWeek
+ const dateInTargetWeek = new Date(root.dateInFirstWeek.getTime() + addedTime);
+ return DateUtils.getIthDayDateOfSameWeek(dateInTargetWeek, root.focusDayOfWeekIndex - (1 * root.american), root.american); // 4 = Thursday
+ }
+ property int focusedMonth: focusedDate.getMonth() + 1 // 0-indexed -> 1-indexed
+
+ // Sizes
+ property real verticalPadding: 0
+ property real buttonSize: 40
+ property real buttonSpacing: 2
+ implicitHeight: (6 * buttonSize) + (5 * buttonSpacing) + (2 * verticalPadding)
+ implicitWidth: weeksColumn.implicitWidth
+ clip: true
+
+ ColumnLayout {
+ id: weeksColumn
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ y: {
+ const spacePerExtraRow = root.buttonSize + root.buttonSpacing;
+ const origin = -(spacePerExtraRow * root.paddingWeeks);
+ const diff = root.weekDiff * spacePerExtraRow;
+ return origin + (-diff % spacePerExtraRow) + root.verticalPadding;
+ }
+
+ spacing: root.buttonSpacing
+ Repeater {
+ model: root.totalWeeks
+ WeekRow {
+ required property int index
+ date: new Date(root.dateInFirstWeek.getTime() + (index * root.millisPerWeek))
+ Layout.fillWidth: true
+ spacing: root.buttonSpacing
+ delegate: root.delegate
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml b/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
new file mode 100644
index 000000000..2863f8896
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
@@ -0,0 +1,43 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.services
+import qs.modules.common.functions
+
+RowLayout {
+ id: root
+
+ // Pls supply
+ required property date date
+ property bool sundayFirst: false
+
+ // Expose model and delegate for flexibility
+ property list model: {
+ // Should expose props like here: https://doc.qt.io/qt-6/qml-qtquick-controls-monthgrid.html#delegate-prop
+ // (except weekNumber because i'm lazy and it's not so important)
+ const firstDayOfWeek = DateUtils.getMonday(root.date, root.sundayFirst);
+ const weekDates = [];
+ for (let i = 0; i < 7; i++) {
+ const dayDate = new Date(firstDayOfWeek);
+ dayDate.setDate(firstDayOfWeek.getDate() + i);
+ weekDates.push({
+ date: dayDate,
+ day: dayDate.getDate(),
+ month: dayDate.getMonth() + 1,
+ year: dayDate.getFullYear(),
+ today: DateUtils.sameDate(dayDate, DateTime.clock.date)
+ });
+ }
+ return weekDates;
+ }
+ property Component delegate: Text {
+ required property var model
+ text: model.day
+ }
+
+ // Obvious
+ Repeater {
+ model: root.model
+ delegate: root.delegate
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
index 0350f5004..e55f840cb 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
@@ -231,5 +231,13 @@ Singleton {
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
+
+ property Component scroll: Component {
+ NumberAnimation {
+ duration: 250
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: [0.0, 0.0, 0.25, 1.0, 1, 1]
+ }
+ }
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
index 18fe0244b..6b2bc4ecb 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
@@ -17,6 +17,7 @@ Button {
property color colBackgroundToggledActive: Looks.colors.accentActive
property color colForeground: Looks.colors.fg
property color colForegroundToggled: Looks.colors.accentFg
+ property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
property alias backgroundOpacity: backgroundRect.opacity
property color color: {
if (!root.enabled) return colBackground;
@@ -37,7 +38,11 @@ Button {
return root.colBackground;
}
}
- property color fgColor: root.checked ? root.colForegroundToggled : root.colForeground
+ property color fgColor: {
+ if (root.checked) return root.colForegroundToggled
+ if (root.enabled) return root.colForeground
+ return root.colForegroundDisabled
+ }
property alias horizontalAlignment: buttonText.horizontalAlignment
font {
family: Looks.font.family.ui
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
deleted file mode 100644
index b0ff57684..000000000
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarView.qml
+++ /dev/null
@@ -1,124 +0,0 @@
-pragma ComponentBehavior: Bound
-import QtQuick
-import QtQuick.Controls
-import QtQuick.Layouts
-import Quickshell
-import qs
-import qs.services
-import qs.modules.common
-import qs.modules.common.functions
-import qs.modules.waffle.looks
-
-// TODO: The overlaps are crazy, but the positioning approach works.
-// This could work well if we do it week by week instead of month by month.
-BodyRectangle {
- id: root
-
- // State
- property bool collapsed
-
- // Sizes
- property int _rowsPerMonth: 6
- property real viewHeight: (_rowsPerMonth * buttonSize) + ((_rowsPerMonth - 1) * buttonSpacing)
- property real buttonSize: 40
- property real buttonSpacing: 2
- property real spacePerExtraRow: buttonSize + buttonSpacing
-
- implicitWidth: currentMonthGrid.implicitWidth
- implicitHeight: collapsed ? 0 : viewHeight
- opacity: implicitHeight > 0 ? 1 : 0
-
- Behavior on implicitHeight {
- animation: Looks.transition.enter.createObject(this)
- }
-
- // Month stuff
- property real targetMonthDiff: 0
- property real monthDiff: targetMonthDiff
- property int focusedMonthDiff: monthDiff // whole part of monthDiff
- property int currentMonth: DateTime.clock.date.getMonth() + 1 // 0-indexed -> 1-indexed
- property int currentYear: DateTime.clock.date.getFullYear()
-
- clip: true
- property list monthGrids: [previousPreviousMonthGrid, previousMonthGrid, currentMonthGrid, nextMonthGrid, nextNextMonthGrid]
- ColumnLayout {
- spacing: 0
- y: {
- const origin = - currentMonthGrid.y;
- const diff = root.monthDiff * root.viewHeight;
- return origin + (-diff % root.viewHeight);
- }
- DiffMonthGrid {
- id: previousPreviousMonthGrid
- monthDiff: root.focusedMonthDiff - 2
- }
- DiffMonthGrid {
- id: previousMonthGrid
- monthDiff: root.focusedMonthDiff - 1
- }
- DiffMonthGrid {
- id: currentMonthGrid
- monthDiff: root.focusedMonthDiff
- }
- DiffMonthGrid {
- id: nextMonthGrid
- monthDiff: root.focusedMonthDiff + 1
- }
- DiffMonthGrid {
- id: nextNextMonthGrid
- monthDiff: root.focusedMonthDiff + 2
- }
- }
-
- MouseArea {
- anchors.fill: parent
- onWheel: wheel => {
- root.targetMonthDiff += wheel.angleDelta.y / 120 * -0.333333; // Reverse cuz scrolling down should advance
- }
- }
-
- Behavior on monthDiff {
- animation: Looks.transition.enter.createObject(this)
- }
-
- component DiffMonthGrid: MonthGrid {
- id: monthGrid
- required property int monthDiff
- property int index: root.monthGrids.indexOf(this)
- month: ((root.currentMonth - 1) + monthDiff) % 12 // 1-indexed -> 0-indexed
- year: root.currentYear + Math.floor((root.currentMonth - 1 + monthDiff) / 12)
-
- spacing: root.buttonSpacing
- // background: Rectangle {
- // color: Qt.rgba(Math.abs(Math.sin(month * 12.9898)) % 1, Math.abs(Math.sin(month * 78.233)) % 1, Math.abs(Math.sin(month * 45.164)) % 1, 1)
- // }
- delegate: MonthDayButton {}
- }
-
- component MonthDayButton: WButton {
- id: monthDayButton
- required property var model
- opacity: model.month == parent.parent.month || model.today ? 1 : 0
- checked: model.today
- implicitWidth: root.buttonSize
- implicitHeight: root.buttonSize
- radius: height / 2
-
- required property int index
-
- contentItem: Item {
- WText {
- anchors.centerIn: parent
- text: monthDayButton.model.day
- color: {
- if (monthDayButton.model.today)
- return Looks.colors.accentFg;
- if (monthDayButton.model.month == root.currentMonth - 1)
- return Looks.colors.fg;
- return Looks.colors.subfg;
- }
- font.pixelSize: Looks.font.pixelSize.large
- }
- }
- }
-}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
new file mode 100644
index 000000000..23fc7c6eb
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
@@ -0,0 +1,132 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+BodyRectangle {
+ id: root
+
+ // State
+ property bool collapsed
+
+ implicitHeight: collapsed ? 0 : contentColumn.implicitHeight
+ implicitWidth: contentColumn.implicitWidth
+
+ Behavior on implicitHeight {
+ animation: Looks.transition.enter.createObject(this)
+ }
+
+ clip: true
+ ColumnLayout {
+ id: contentColumn
+ spacing: 12
+ CalendarHeader {
+ Layout.topMargin: 10
+ Layout.fillWidth: true
+ }
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: 5
+ Layout.rightMargin: 5
+ spacing: 1
+ DayOfWeekRow {
+ Layout.fillWidth: true
+ locale: Qt.locale("en-GB")
+ spacing: calendarView.buttonSpacing
+ implicitHeight: calendarView.buttonSize
+ delegate: Item {
+ id: dayOfWeekItem
+ required property var model
+ implicitHeight: calendarView.buttonSize
+ implicitWidth: calendarView.buttonSize
+ WText {
+ anchors.centerIn: parent
+ text: dayOfWeekItem.model.shortName.substring(0,2)
+ color: Looks.colors.fg
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+ }
+ }
+ CalendarView {
+ id: calendarView
+ verticalPadding: 2
+ buttonSize: 41 // ???
+ buttonSpacing: 1
+ Layout.fillWidth: true
+ delegate: DayButton {}
+ }
+ }
+ }
+
+ component DayButton: WButton {
+ id: dayButton
+ required property var model
+ checked: model.today
+ enabled: hovered || calendarView.scrolling || checked || model.month === calendarView.focusedMonth
+ implicitWidth: calendarView.buttonSize
+ implicitHeight: calendarView.buttonSize
+ radius: height / 2
+
+ required property int index
+
+ contentItem: Item {
+ WText {
+ anchors.centerIn: parent
+ text: dayButton.model.day
+ color: dayButton.fgColor
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+ }
+ }
+
+ component CalendarHeader: RowLayout {
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ spacing: 8
+
+ WBorderlessButton {
+ Layout.fillWidth: true
+ implicitHeight: 34
+ contentItem: Item {
+ WText {
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignLeft
+ text: Qt.locale().toString(calendarView.dateInFirstWeek, "MMMM yyyy")
+ font.pixelSize: Looks.font.pixelSize.large
+ font.weight: Looks.font.weight.strong
+ }
+ }
+ }
+ ScrollMonthButton {
+ scrollDown: false
+ }
+ ScrollMonthButton {
+ scrollDown: true
+ }
+ }
+
+ component ScrollMonthButton: WBorderlessButton {
+ id: scrollMonthButton
+ required property bool scrollDown
+ Layout.alignment: Qt.AlignVCenter
+
+ onClicked: {
+ calendarView.scrollMonthsAndSnap(scrollDown ? 1 : -1);
+ }
+ implicitWidth: 32
+ implicitHeight: 34
+
+ contentItem: FluentIcon {
+ filled: true
+ implicitSize: 12
+ icon: scrollMonthButton.scrollDown ? "caret-down" : "caret-up"
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/DateHeader.qml
similarity index 87%
rename from dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
rename to dots/.config/quickshell/ii/modules/waffle/notificationCenter/DateHeader.qml
index 3e177f2fa..99e0666ed 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarHeader.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/DateHeader.qml
@@ -12,8 +12,12 @@ import qs.modules.waffle.looks
FooterRectangle {
id: root
- property bool collapsed
implicitWidth: 0
+ property bool collapsed
+ color: ColorUtils.transparentize(Looks.colors.bgPanelBody, collapsed ? 0 : 1)
+ Behavior on color {
+ animation: Looks.transition.color.createObject(this)
+ }
RowLayout {
anchors {
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
index c66925d04..c222e41c4 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
@@ -12,6 +12,7 @@ import qs.modules.waffle.looks
FooterRectangle {
Layout.fillWidth: true
implicitWidth: 0
+ color: Looks.colors.bgPanelBody
RowLayout {
anchors {
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
index c2b97f6dc..ed6677854 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -30,7 +30,7 @@ WBarAttachedPanelContent {
WPane {
contentItem: ColumnLayout {
spacing: 0
- CalendarHeader {
+ DateHeader {
Layout.fillWidth: true
Synchronizer on collapsed {
property alias source: root.collapsed
@@ -39,8 +39,8 @@ WBarAttachedPanelContent {
WPanelSeparator { visible: !root.collapsed }
- CalendarView {
- // Layout.fillWidth: true
+ CalendarWidget {
+ Layout.fillWidth: true
Synchronizer on collapsed {
property alias source: root.collapsed
}
From d40df98aa585894b9ce246119301d5c54c465c08 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 27 Nov 2025 08:14:15 +0100
Subject: [PATCH 018/154] =?UTF-8?q?waffles:=20make=20calendar=20more=20?=
=?UTF-8?q?=F0=9F=8D=94=F0=9F=A6=85-friendly?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
do we care about somalia and ethiopia
---
dots/.config/quickshell/ii/modules/common/Config.qml | 6 +++++-
.../quickshell/ii/modules/common/widgets/CalendarView.qml | 7 ++++++-
.../modules/waffle/notificationCenter/CalendarWidget.qml | 7 ++++++-
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index 610a4959d..e5285d416 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -282,6 +282,10 @@ Singleton {
property int suspend: 3
}
+ property JsonObject calendar: JsonObject {
+ property bool forceMondayWeekStart: true
+ }
+
property JsonObject cheatsheet: JsonObject {
// Use a nerdfont to see the icons
// 0: | 1: | 2: | 3: | 4:
@@ -581,7 +585,7 @@ Singleton {
}
property JsonObject waffles: JsonObject {
- // Animations on Windoes are kinda janky. Setting the following to
+ // Some spots are kinda janky/awkward. Setting the following to
// false will make (some) stuff also be like that for accuracy.
// Example: the right-click menu of the Start button
property JsonObject tweaks: JsonObject {
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
index 56997ecba..44d64efd5 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
@@ -1,4 +1,5 @@
pragma ComponentBehavior: Bound
+import QtQml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -21,7 +22,8 @@ Item {
// Configuration
property int paddingWeeks: 2 // 1 should be sufficient with proper clipping and no padding
- property bool american: false // 🍔🦅 = Sunday first
+ property var locale: Qt.locale() // Should be of type Locale but QML is being funny
+ property bool american: locale.firstDayOfWeek == Locale.Sunday
// Scrolling
function scrollMonthsAndSnap(x) { // Scroll x months and snap to month
@@ -104,10 +106,13 @@ Item {
}
spacing: root.buttonSpacing
+
Repeater {
model: root.totalWeeks
+
WeekRow {
required property int index
+ sundayFirst: root.american
date: new Date(root.dateInFirstWeek.getTime() + (index * root.millisPerWeek))
Layout.fillWidth: true
spacing: root.buttonSpacing
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
index 23fc7c6eb..5b595de31 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
@@ -1,4 +1,5 @@
pragma ComponentBehavior: Bound
+import QtQml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -16,6 +17,9 @@ BodyRectangle {
// State
property bool collapsed
+ // Locale
+ property var locale: Config.options.calendar.forceMondayWeekStart ? Qt.locale("en-GB") : Qt.locale()
+
implicitHeight: collapsed ? 0 : contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth
@@ -38,7 +42,7 @@ BodyRectangle {
spacing: 1
DayOfWeekRow {
Layout.fillWidth: true
- locale: Qt.locale("en-GB")
+ locale: root.locale
spacing: calendarView.buttonSpacing
implicitHeight: calendarView.buttonSize
delegate: Item {
@@ -56,6 +60,7 @@ BodyRectangle {
}
CalendarView {
id: calendarView
+ locale: root.locale
verticalPadding: 2
buttonSize: 41 // ???
buttonSpacing: 1
From 0700e024d9742776fdc5d6cd4dbdf7ca631e2488 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 27 Nov 2025 13:17:24 +0100
Subject: [PATCH 019/154] waffles: calendar: generalize first day of week
---
.../quickshell/ii/modules/common/Config.qml | 5 +++-
.../ii/modules/common/functions/DateUtils.qml | 29 ++++++-------------
.../modules/common/widgets/CalendarView.qml | 7 ++---
.../ii/modules/common/widgets/WeekRow.qml | 6 ++--
.../notificationCenter/CalendarWidget.qml | 10 +++++--
5 files changed, 26 insertions(+), 31 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index e5285d416..1716aa2ef 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -283,7 +283,7 @@ Singleton {
}
property JsonObject calendar: JsonObject {
- property bool forceMondayWeekStart: true
+ property string locale: "en-GB"
}
property JsonObject cheatsheet: JsonObject {
@@ -599,6 +599,9 @@ Singleton {
property JsonObject actionCenter: JsonObject {
property list toggles: [ "network", "bluetooth", "easyEffects", "powerProfile", "idleInhibitor", "nightLight", "darkMode", "antiFlashbang", "cloudflareWarp", "mic", "musicRecognition", "notifications", "onScreenKeyboard", "gameMode", "screenSnip", "colorPicker" ]
}
+ property JsonObject calendar: JsonObject {
+ property bool force2CharDayOfWeek: true
+ }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml b/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
index a7527bcb8..3cbae5bee 100644
--- a/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
+++ b/dots/.config/quickshell/ii/modules/common/functions/DateUtils.qml
@@ -4,35 +4,24 @@ import Quickshell
Singleton {
id: root
- function getMonday(date, american = false) {
+ function getFirstDayOfWeek(date, firstDay = 1) {
const d = new Date(date); // Copy
const day = d.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
- // Calculate difference to Monday
- if (american) {
- // Week starts on Sunday
- d.setDate(d.getDate() - day);
- } else {
- // Week starts on Monday
- const diff = day === 0 ? -6 : 1 - day;
- d.setDate(d.getDate() + diff);
- }
-
+ // Calculate difference to firstDay
+ const diff = (day - firstDay + 7) % 7;
+ d.setDate(d.getDate() - diff);
return d;
}
function sameDate(d1, d2) {
- return (
- d1.getFullYear() === d2.getFullYear() &&
- d1.getMonth() === d2.getMonth() &&
- d1.getDate() === d2.getDate()
- );
+ return (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate());
}
- function getIthDayDateOfSameWeek(date, i, american = false) {
- const monday = root.getMonday(date, american);
- const targetDate = new Date(monday);
- targetDate.setDate(monday.getDate() + i);
+ function getIthDayDateOfSameWeek(date, i, firstDay = 1) {
+ const firstDayDate = root.getFirstDayOfWeek(date, firstDay);
+ const targetDate = new Date(firstDayDate);
+ targetDate.setDate(firstDayDate.getDate() + i);
return targetDate;
}
}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
index 44d64efd5..648da466a 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/CalendarView.qml
@@ -23,7 +23,6 @@ Item {
// Configuration
property int paddingWeeks: 2 // 1 should be sufficient with proper clipping and no padding
property var locale: Qt.locale() // Should be of type Locale but QML is being funny
- property bool american: locale.firstDayOfWeek == Locale.Sunday
// Scrolling
function scrollMonthsAndSnap(x) { // Scroll x months and snap to month
@@ -68,7 +67,7 @@ Item {
readonly property int millisPerWeek: 7 * 24 * 60 * 60 * 1000
readonly property int totalWeeks: 6 + (paddingWeeks * 2)
readonly property int focusedWeekIndex: 2 // The third row, 0-indexed
- readonly property int focusDayOfWeekIndex: 6 // Non-American
+ readonly property int focusDayOfWeekIndex: 6
property date dateInFirstWeek: {
const currentDate = new Date();
const currentMonth = currentDate.getMonth();
@@ -80,7 +79,7 @@ Item {
// The last day of 3rd week shown is considered the focused month
const addedTime = (root.paddingWeeks + root.focusedWeekIndex) * root.millisPerWeek
const dateInTargetWeek = new Date(root.dateInFirstWeek.getTime() + addedTime);
- return DateUtils.getIthDayDateOfSameWeek(dateInTargetWeek, root.focusDayOfWeekIndex - (1 * root.american), root.american); // 4 = Thursday
+ return DateUtils.getIthDayDateOfSameWeek(dateInTargetWeek, root.focusDayOfWeekIndex - root.locale.firstDayOfWeek, root.locale.firstdayOfWeek); // 4 = Thursday
}
property int focusedMonth: focusedDate.getMonth() + 1 // 0-indexed -> 1-indexed
@@ -112,7 +111,7 @@ Item {
WeekRow {
required property int index
- sundayFirst: root.american
+ locale: root.locale
date: new Date(root.dateInFirstWeek.getTime() + (index * root.millisPerWeek))
Layout.fillWidth: true
spacing: root.buttonSpacing
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml b/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
index 2863f8896..93fc536d2 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/WeekRow.qml
@@ -8,14 +8,14 @@ RowLayout {
id: root
// Pls supply
- required property date date
- property bool sundayFirst: false
+ required property date date // Any date within the week
+ property var locale
// Expose model and delegate for flexibility
property list model: {
// Should expose props like here: https://doc.qt.io/qt-6/qml-qtquick-controls-monthgrid.html#delegate-prop
// (except weekNumber because i'm lazy and it's not so important)
- const firstDayOfWeek = DateUtils.getMonday(root.date, root.sundayFirst);
+ const firstDayOfWeek = DateUtils.getFirstDayOfWeek(root.date, root.locale.firstDayOfWeek);
const weekDates = [];
for (let i = 0; i < 7; i++) {
const dayDate = new Date(firstDayOfWeek);
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
index 5b595de31..0ac48d13b 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/CalendarWidget.qml
@@ -18,7 +18,7 @@ BodyRectangle {
property bool collapsed
// Locale
- property var locale: Config.options.calendar.forceMondayWeekStart ? Qt.locale("en-GB") : Qt.locale()
+ property var locale: Qt.locale(Config.options.calendar.locale)
implicitHeight: collapsed ? 0 : contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth
@@ -52,7 +52,11 @@ BodyRectangle {
implicitWidth: calendarView.buttonSize
WText {
anchors.centerIn: parent
- text: dayOfWeekItem.model.shortName.substring(0,2)
+ text: {
+ var result = dayOfWeekItem.model.shortName;
+ if (Config.options.waffles.calendar.force2CharDayOfWeek) result = result.substring(0,2);
+ return result;
+ }
color: Looks.colors.fg
font.pixelSize: Looks.font.pixelSize.large
}
@@ -103,7 +107,7 @@ BodyRectangle {
WText {
anchors.fill: parent
horizontalAlignment: Text.AlignLeft
- text: Qt.locale().toString(calendarView.dateInFirstWeek, "MMMM yyyy")
+ text: Qt.locale().toString(calendarView.focusedDate, "MMMM yyyy")
font.pixelSize: Looks.font.pixelSize.large
font.weight: Looks.font.weight.strong
}
From 9cb5cc1416ca9d98118c464ffcc5c9536a9f4207 Mon Sep 17 00:00:00 2001
From: jwihardi
Date: Thu, 27 Nov 2025 15:29:30 -0500
Subject: [PATCH 020/154] added gentoo uninstall
---
sdata/dist-gentoo/uninstall-deps.sh | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 sdata/dist-gentoo/uninstall-deps.sh
diff --git a/sdata/dist-gentoo/uninstall-deps.sh b/sdata/dist-gentoo/uninstall-deps.sh
new file mode 100644
index 000000000..280433946
--- /dev/null
+++ b/sdata/dist-gentoo/uninstall-deps.sh
@@ -0,0 +1,8 @@
+# This script is meant to be sourced.
+# It's not for directly running.
+
+for i in illogical-impulse-{quickshell-git,audio,backlight,basic,bibata-modern-classic-bin,fonts-themes,hyprland,kde,microtex-git,oneui4-icons-git,portal,python,screencapture,toolkit,widgets}; do
+ v sudo emerge --unmerge $i
+done
+
+v sudo emerge --depclean
From 2fd25af353fd963c13ef35d07325b9143f3b4a48 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Thu, 27 Nov 2025 23:25:59 +0100
Subject: [PATCH 021/154] waffles: notifications, kind of
---
.../ii/assets/icons/fluent/apps-filled.svg | 4 +
.../ii/assets/icons/fluent/apps.svg | 4 +
.../icons/fluent/more-horizontal-filled.svg | 4 +
.../assets/icons/fluent/more-horizontal.svg | 4 +
.../common/functions/NotificationUtils.qml | 87 +++++++++++++++++
.../common/widgets/NotificationAppIcon.qml | 2 +-
.../common/widgets/NotificationGroup.qml | 7 +-
.../common/widgets/notification_utils.js | 82 ----------------
.../modules/waffle/looks/WBorderedButton.qml | 6 +-
.../ii/modules/waffle/looks/WPane.qml | 1 +
.../waffle/notificationCenter/FocusFooter.qml | 28 ++----
.../NotificationCenterContent.qml | 34 ++++++-
.../NotificationHeaderButton.qml | 25 +++++
.../NotificationPaneContent.qml | 81 ++++++++++++++++
.../SmallBorderedIconAndTextButton.qml | 34 +++++++
.../SmallBorderedIconButton.qml | 1 +
.../WNotificationAppIcon.qml | 30 ++++++
.../notificationCenter/WNotificationGroup.qml | 93 +++++++++++++++++++
.../WSingleNotification.qml | 59 ++++++++++++
19 files changed, 470 insertions(+), 116 deletions(-)
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/apps-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/apps.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal.svg
create mode 100644 dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
delete mode 100644 dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationAppIcon.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/apps-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/apps-filled.svg
new file mode 100644
index 000000000..88214527a
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/apps-filled.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/apps.svg b/dots/.config/quickshell/ii/assets/icons/fluent/apps.svg
new file mode 100644
index 000000000..5eb188422
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/apps.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal-filled.svg
new file mode 100644
index 000000000..5b5a33c9f
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal-filled.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal.svg b/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal.svg
new file mode 100644
index 000000000..57e2ee132
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/more-horizontal.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
new file mode 100644
index 000000000..8a336e8ad
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
@@ -0,0 +1,87 @@
+pragma Singleton
+import Quickshell
+
+Singleton {
+ id: root
+ /**
+ * @param { string } summary
+ * @returns { string }
+ */
+ function findSuitableMaterialSymbol(summary = "") {
+ const defaultType = 'chat';
+ if (summary.length === 0) return defaultType;
+
+ const keywordsToTypes = {
+ 'reboot': 'restart_alt',
+ 'record': 'screen_record',
+ 'battery': 'power',
+ 'power': 'power',
+ 'screenshot': 'screenshot_monitor',
+ 'welcome': 'waving_hand',
+ 'time': 'scheduleb',
+ 'installed': 'download',
+ 'configuration reloaded': 'reset_wrench',
+ 'unable': 'question_mark',
+ "couldn't": 'question_mark',
+ 'config': 'reset_wrench',
+ 'update': 'update',
+ 'ai response': 'neurology',
+ 'control': 'settings',
+ 'upsca': 'compare',
+ 'music': 'queue_music',
+ 'install': 'deployed_code_update',
+ 'input': 'keyboard_alt',
+ 'preedit': 'keyboard_alt',
+ 'startswith:file': 'folder_copy', // Declarative startsWith check
+ };
+
+ const lowerSummary = summary.toLowerCase();
+
+ for (const [keyword, type] of Object.entries(keywordsToTypes)) {
+ if (keyword.startsWith('startswith:')) {
+ const startsWithKeyword = keyword.replace('startswith:', '');
+ if (lowerSummary.startsWith(startsWithKeyword)) {
+ return type;
+ }
+ } else if (lowerSummary.includes(keyword)) {
+ return type;
+ }
+ }
+
+ return defaultType;
+ }
+
+ /**
+ * @param { number | string | Date } timestamp
+ * @returns { string }
+ */
+ function getFriendlyNotifTimeString(timestamp) {
+ if (!timestamp) return '';
+ const messageTime = new Date(timestamp);
+ const now = new Date();
+ const diffMs = now.getTime() - messageTime.getTime();
+
+ // Less than 1 minute
+ if (diffMs < 60000)
+ return 'Now';
+
+ // Same day - show relative time
+ if (messageTime.toDateString() === now.toDateString()) {
+ const diffMinutes = Math.floor(diffMs / 60000);
+ const diffHours = Math.floor(diffMs / 3600000);
+
+ if (diffHours > 0) {
+ return `${diffHours}h`;
+ } else {
+ return `${diffMinutes}m`;
+ }
+ }
+
+ // Yesterday
+ if (messageTime.toDateString() === new Date(now.getTime() - 86400000).toDateString())
+ return 'Yesterday';
+
+ // Older dates
+ return Qt.formatDateTime(messageTime, "MMMM dd");
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml b/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml
index b590f22ac..ad250d9b6 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml
@@ -1,5 +1,5 @@
import qs.modules.common
-import "notification_utils.js" as NotificationUtils
+import qs.modules.common.functions
import Qt5Compat.GraphicalEffects
import QtQuick
import Quickshell
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml b/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml
index b20b470fa..fc612dcb1 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml
@@ -1,7 +1,6 @@
import qs.services
import qs.modules.common
import qs.modules.common.functions
-import "notification_utils.js" as NotificationUtils
import QtQuick
import QtQuick.Layouts
import Quickshell
@@ -136,7 +135,7 @@ MouseArea { // Notification group area
}
clip: true
- implicitHeight: expanded ?
+ implicitHeight: root.expanded ?
row.implicitHeight + padding * 2 :
Math.min(80, row.implicitHeight + padding * 2)
@@ -157,8 +156,8 @@ MouseArea { // Notification group area
Layout.alignment: Qt.AlignTop
Layout.fillWidth: false
image: root?.multipleNotifications ? "" : notificationGroup?.notifications[0]?.image ?? ""
- appIcon: notificationGroup?.appIcon
- summary: notificationGroup?.notifications[root.notificationCount - 1]?.summary
+ appIcon: root.notificationGroup?.appIcon
+ summary: root.notificationGroup?.notifications[root.notificationCount - 1]?.summary
urgency: root.notifications.some(n => n.urgency === NotificationUrgency.Critical.toString()) ?
NotificationUrgency.Critical : NotificationUrgency.Normal
}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js
deleted file mode 100644
index 1f879baa2..000000000
--- a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js
+++ /dev/null
@@ -1,82 +0,0 @@
-
-/**
- * @param { string } summary
- * @returns { string }
- */
-function findSuitableMaterialSymbol(summary = "") {
- const defaultType = 'chat';
- if(summary.length === 0) return defaultType;
-
- const keywordsToTypes = {
- 'reboot': 'restart_alt',
- 'record': 'screen_record',
- 'battery': 'power',
- 'power': 'power',
- 'screenshot': 'screenshot_monitor',
- 'welcome': 'waving_hand',
- 'time': 'scheduleb',
- 'installed': 'download',
- 'configuration reloaded': 'reset_wrench',
- 'unable': 'question_mark',
- "couldn't": 'question_mark',
- 'config': 'reset_wrench',
- 'update': 'update',
- 'ai response': 'neurology',
- 'control': 'settings',
- 'upsca': 'compare',
- 'music': 'queue_music',
- 'install': 'deployed_code_update',
- 'input': 'keyboard_alt',
- 'preedit': 'keyboard_alt',
- 'startswith:file': 'folder_copy', // Declarative startsWith check
- };
-
- const lowerSummary = summary.toLowerCase();
-
- for (const [keyword, type] of Object.entries(keywordsToTypes)) {
- if (keyword.startsWith('startswith:')) {
- const startsWithKeyword = keyword.replace('startswith:', '');
- if (lowerSummary.startsWith(startsWithKeyword)) {
- return type;
- }
- } else if (lowerSummary.includes(keyword)) {
- return type;
- }
- }
-
- return defaultType;
-}
-
-/**
- * @param { number | string | Date } timestamp
- * @returns { string }
- */
-const getFriendlyNotifTimeString = (timestamp) => {
- if (!timestamp) return '';
- const messageTime = new Date(timestamp);
- const now = new Date();
- const diffMs = now.getTime() - messageTime.getTime();
-
- // Less than 1 minute
- if (diffMs < 60000)
- return 'Now';
-
- // Same day - show relative time
- if (messageTime.toDateString() === now.toDateString()) {
- const diffMinutes = Math.floor(diffMs / 60000);
- const diffHours = Math.floor(diffMs / 3600000);
-
- if (diffHours > 0) {
- return `${diffHours}h`;
- } else {
- return `${diffMinutes}m`;
- }
- }
-
- // Yesterday
- if (messageTime.toDateString() === new Date(now.getTime() - 86400000).toDateString())
- return 'Yesterday';
-
- // Older dates
- return Qt.formatDateTime(messageTime, "MMMM dd");
-};
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
index 74cb35f8b..b3377cc64 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderedButton.qml
@@ -11,8 +11,8 @@ WButton {
colBackground: Looks.colors.bg2
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
- border.color: Looks.colors.bg2Border
+ property color colBorder: Looks.colors.bg2Border
+ property color colBorderToggled: Looks.colors.accent
+ border.color: checked ? colBorderToggled : colBorder
border.width: root.pressed ? 2 : 1
-
-
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
index 68e836b66..be75cc30a 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml
@@ -14,6 +14,7 @@ Item {
property real radius: Looks.radius.large
property alias border: borderRect
property alias borderColor: borderRect.border.color
+ property alias borderWidth: borderRect.border.width
implicitWidth: borderRect.implicitWidth
implicitHeight: borderRect.implicitHeight
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
index c222e41c4..2f2b788a4 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/FocusFooter.qml
@@ -54,35 +54,19 @@ FooterRectangle {
Layout.fillWidth: true
}
- SmallBorderedIconButton {
- leftPadding: 12
- rightPadding: 12
- implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
+ SmallBorderedIconAndTextButton {
+ iconName: TimerService.pomodoroRunning ? "stop" : "play"
+ text: TimerService.pomodoroRunning ? Translation.tr("End session") : Translation.tr("Focus")
onClicked: {
if (TimerService.pomodoroRunning) {
- TimerService.togglePomodoro()
- TimerService.resetPomodoro()
+ TimerService.togglePomodoro();
+ TimerService.resetPomodoro();
} else {
- TimerService.togglePomodoro()
+ TimerService.togglePomodoro();
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "sidebarRight", "toggle"]);
}
}
-
- contentItem: Row {
- id: focusButtonContent
- spacing: 4
- FluentIcon {
- icon: TimerService.pomodoroRunning ? "stop" : "play"
- filled: true
- implicitSize: 14
- anchors.verticalCenter: parent.verticalCenter
- }
- WText {
- anchors.verticalCenter: parent.verticalCenter
- text: TimerService.pomodoroRunning ? Translation.tr("End session") : Translation.tr("Focus")
- }
- }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
index ed6677854..797cee28a 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -19,16 +19,40 @@ WBarAttachedPanelContent {
property bool collapsed: false
- contentItem: Column {
+ contentItem: ColumnLayout {
anchors {
horizontalCenter: parent.horizontalCenter
- top: root.barAtBottom ? undefined : parent.top
- bottom: root.barAtBottom ? parent.bottom : undefined
+ top: parent.top
+ bottom: parent.bottom
}
spacing: 12
+ Item {
+ id: notificationArea
+ Layout.fillHeight: true
+ implicitWidth: notificationPane.implicitWidth
+
+ WPane {
+ id: notificationPane
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+ contentItem: NotificationPaneContent {
+ implicitWidth: calendarColumnLayout.implicitWidth
+ implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230
+
+ Behavior on implicitHeight {
+ animation: Looks.transition.enter.createObject(this)
+ }
+ }
+ }
+ }
+
WPane {
contentItem: ColumnLayout {
+ id: calendarColumnLayout
spacing: 0
DateHeader {
Layout.fillWidth: true
@@ -37,7 +61,9 @@ WBarAttachedPanelContent {
}
}
- WPanelSeparator { visible: !root.collapsed }
+ WPanelSeparator {
+ visible: !root.collapsed
+ }
CalendarWidget {
Layout.fillWidth: true
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
new file mode 100644
index 000000000..860451fc3
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
@@ -0,0 +1,25 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+WBorderlessButton {
+ id: headerButton
+ Layout.fillWidth: false
+ implicitWidth: 16
+ implicitHeight: 16
+ color: "transparent"
+
+ contentItem: Item {
+ FluentIcon {
+ anchors.centerIn: parent
+ implicitSize: 16
+ icon: headerButton.icon.name
+ color: headerButton.hovered && !headerButton.pressed ? Looks.colors.fg : Looks.colors.fg1
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml
new file mode 100644
index 000000000..368829865
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml
@@ -0,0 +1,81 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+BodyRectangle {
+ id: root
+ anchors.fill: parent
+ implicitHeight: 230
+
+ ColumnLayout {
+ id: contentLayout
+ anchors.fill: parent
+ anchors.margins: 4
+
+ spacing: 12
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+ Layout.topMargin: 8
+
+ spacing: 8
+
+ WText {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight
+ text: Translation.tr("Notifications")
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+
+ SmallBorderedIconButton {
+ icon.name: "alert-snooze"
+ checked: Notifications.silent
+ onClicked: {
+ Notifications.silent = !Notifications.silent;
+ }
+ }
+
+ SmallBorderedIconAndTextButton {
+ visible: Notifications.list.length > 0
+ iconVisible: false
+ text: Translation.tr("Clear all")
+ onClicked: {
+ Notifications.discardAllNotifications();
+ }
+ }
+ }
+
+ StyledListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ animateAppearance: false
+ clip: true
+
+ model: Notifications.appNameList
+ delegate: WNotificationGroup {
+ required property int index
+ required property var modelData
+ width: ListView.view.width
+ notificationGroup: Notifications.groupsByAppName[modelData]
+ }
+
+ EmptyPlaceholder {
+ visible: Notifications.list.length === 0
+ anchors.centerIn: parent
+ }
+ }
+ }
+
+ component EmptyPlaceholder: WText {
+ horizontalAlignment: Text.AlignHCenter
+ text: Translation.tr("No new notifications")
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
new file mode 100644
index 000000000..c4331a7dc
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
@@ -0,0 +1,34 @@
+import QtQuick
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.waffle.looks
+
+SmallBorderedIconButton {
+ id: root
+
+ property bool iconVisible: true
+ property string iconName: ""
+ property bool iconFilled: true
+
+ leftPadding: 12
+ rightPadding: 12
+ implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
+
+ contentItem: Row {
+ id: focusButtonContent
+ spacing: 4
+
+ FluentIcon {
+ visible: root.iconVisible
+ icon: root.iconName
+ filled: root.iconFilled
+ implicitSize: 14
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ WText {
+ anchors.verticalCenter: parent.verticalCenter
+ text: root.text
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
index 1236779a7..f7006ca7f 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconButton.qml
@@ -13,6 +13,7 @@ WBorderedButton {
anchors.centerIn: parent
implicitSize: 12
icon: root.icon.name
+ color: root.fgColor
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationAppIcon.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationAppIcon.qml
new file mode 100644
index 000000000..a658695d1
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationAppIcon.qml
@@ -0,0 +1,30 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import org.kde.kirigami as Kirigami
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+Item {
+ id: root
+
+ property string icon: ""
+ property real implicitSize: 16
+ implicitWidth: implicitSize
+ implicitHeight: implicitSize
+
+ Kirigami.Icon {
+ anchors.fill: parent
+ implicitWidth: root.implicitSize
+ implicitHeight: root.implicitSize
+
+ source: root.icon || fallback
+ fallback: `${Looks.iconsPath}/apps.svg`
+ roundToIconSize: false
+ isMask: !root.icon
+ color: Looks.colors.fg
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
new file mode 100644
index 000000000..837c7c016
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
@@ -0,0 +1,93 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+MouseArea {
+ id: root
+
+ required property var notificationGroup
+ readonly property var notifications: notificationGroup?.notifications ?? []
+
+ implicitWidth: contentLayout.implicitWidth
+ implicitHeight: contentLayout.implicitHeight
+
+ ColumnLayout {
+ id: contentLayout
+ anchors.fill: parent
+ spacing: 4
+
+ GroupHeader {
+ id: notifHeader
+ Layout.fillWidth: true
+ Layout.margins: 11
+ }
+
+ ListView {
+ Layout.fillWidth: true
+ implicitWidth: notifHeader.implicitWidth
+ implicitHeight: contentHeight
+ interactive: false
+ spacing: 4
+ model: ScriptModel {
+ values: root.notifications.slice().reverse()
+ }
+ delegate: WSingleNotification {
+ required property var modelData
+ width: ListView.view.width
+ notification: modelData
+ }
+ }
+ }
+
+ component GroupHeader: MouseArea {
+ id: headerMouseArea
+ hoverEnabled: true
+ acceptedButtons: Qt.NoButton
+
+ implicitWidth: appHeader.implicitWidth
+ implicitHeight: appHeader.implicitHeight
+
+ RowLayout {
+ id: appHeader
+ anchors.fill: parent
+ spacing: 7
+
+ WNotificationAppIcon {
+ Layout.alignment: Qt.AlignVCenter
+ icon: root.notificationGroup?.appIcon ?? ""
+ }
+
+ WText {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight
+ text: root.notificationGroup?.appName ?? ""
+ }
+
+ // NotificationHeaderButton { // TODO: More notification functionality needed so we can have this button
+ // visible: headerMouseArea.containsMouse
+ // Layout.leftMargin: 25
+ // Layout.rightMargin: 25
+ // icon.name: "more-horizontal"
+ // }
+
+ NotificationHeaderButton {
+ visible: headerMouseArea.containsMouse
+ Layout.rightMargin: 3
+ icon.name: "dismiss"
+ onClicked: {
+ root.notifications.forEach(notif => {
+ Qt.callLater(() => {
+ Notifications.discardNotification(notif.notificationId);
+ });
+ });
+ }
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
new file mode 100644
index 000000000..42a832adb
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
@@ -0,0 +1,59 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import Quickshell.Services.Notifications
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+MouseArea {
+ id: root
+
+ required property var notification
+ property bool expanded: false
+
+ implicitHeight: contentItem.implicitHeight
+ implicitWidth: contentItem.implicitWidth
+
+ Rectangle {
+ id: contentItem
+ anchors.fill: parent
+ color: Looks.colors.bgPanelBody
+ radius: Looks.radius.medium
+ property real padding: 12
+ implicitHeight: notificationContent.implicitHeight + padding * 2
+ implicitWidth: notificationContent.implicitWidth + padding * 2
+ border.width: 1
+ border.color: Looks.applyContentTransparency(Looks.colors.ambientShadow)
+
+ ColumnLayout {
+ id: notificationContent
+ anchors.fill: parent
+ anchors.margins: contentItem.padding
+
+ RowLayout {
+ Layout.fillWidth: true
+ WText {
+ text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
+ }
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ WText {
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ text: root.notification.summary
+ }
+ WText {
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ wrapMode: Text.Wrap
+ maximumLineCount: root.expanded ? 100 : 1
+ }
+ }
+ }
+ }
+}
From 2a1aaa9b7e34b11413b0bbfc4dec6f0ba087f81c Mon Sep 17 00:00:00 2001
From: Perdixky <3293789706@qq.com>
Date: Fri, 28 Nov 2025 14:07:58 +0800
Subject: [PATCH 022/154] config: use KDE network manager GUI for WiFi settings
Replace nmtui (terminal UI) with kcmshell6 kcm_networkmanagement for
network settings to match the Bluetooth settings UI style and provide
a more consistent graphical user experience.
---
dots/.config/quickshell/ii/modules/common/Config.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index 1716aa2ef..0cf28653a 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -153,7 +153,7 @@ Singleton {
property JsonObject apps: JsonObject {
property string bluetooth: "kcmshell6 kcm_bluetooth"
- property string network: "kitty -1 fish -c nmtui"
+ property string network: "kcmshell6 kcm_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
From b214993c161b995cc214d320bd8dc5cf51ae1c43 Mon Sep 17 00:00:00 2001
From: eren <98850034+EisregenHaha@users.noreply.github.com>
Date: Fri, 28 Nov 2025 12:51:19 +0100
Subject: [PATCH 023/154] Add Qalculate as Dependency for Fedora
fixes math
---
sdata/dist-fedora/feddeps.toml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sdata/dist-fedora/feddeps.toml b/sdata/dist-fedora/feddeps.toml
index f21169a1b..2a1bf2df5 100644
--- a/sdata/dist-fedora/feddeps.toml
+++ b/sdata/dist-fedora/feddeps.toml
@@ -181,6 +181,7 @@ packages = [
"hyprpicker",
"songrec",
"translate-shell",
+ "qalculate",
"wlogout"
]
@@ -191,4 +192,4 @@ packages = [
"plasma-systemmonitor",
"unzip"
]
-install_opts = ["--setopt=install_weak_deps=False"]
\ No newline at end of file
+install_opts = ["--setopt=install_weak_deps=False"]
From 04f73e67c8eee60ccf1fdf553e46c246c6948c01 Mon Sep 17 00:00:00 2001
From: clsty
Date: Fri, 28 Nov 2025 21:07:39 +0800
Subject: [PATCH 024/154] Add qalc dep for dist-arch and deps-info (#2591)
---
sdata/deps-info.md | 3 +++
sdata/dist-arch/illogical-impulse-widgets/PKGBUILD | 3 ++-
sdata/dist-fedora/feddeps.toml | 1 +
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/sdata/deps-info.md b/sdata/deps-info.md
index fc6f315a3..9a1e4e826 100644
--- a/sdata/deps-info.md
+++ b/sdata/deps-info.md
@@ -191,6 +191,9 @@ Tips:
- Used in Quickshell config.
- `wlogout`
- Used in Hyprland config.
+- `libqalculate`
+ - Used in Quickshell config, providing math ability in searchbar.
+ - Note that `qalc` is the needed executable. In Arch Linux [libqalculate](https://archlinux.org/packages/extra/x86_64/libqalculate) provides it, but in Fedora [qalculate](https://packages.fedoraproject.org/pkgs/libqalculate/qalculate/fedora-43.html#files) does and [libqalculate](https://packages.fedoraproject.org/pkgs/libqalculate/libqalculate/fedora-43.html#files) does not.
# Actual packages
diff --git a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
index 76f71d43f..fa9d4df02 100644
--- a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
@@ -1,6 +1,6 @@
pkgname=illogical-impulse-widgets
pkgver=1.0
-pkgrel=5
+pkgrel=6
pkgdesc='Illogical Impulse Widget Dependencies'
arch=(any)
license=(None)
@@ -14,4 +14,5 @@ depends=(
songrec
translate-shell
wlogout
+ libqalculate
)
diff --git a/sdata/dist-fedora/feddeps.toml b/sdata/dist-fedora/feddeps.toml
index 2a1bf2df5..367626ced 100644
--- a/sdata/dist-fedora/feddeps.toml
+++ b/sdata/dist-fedora/feddeps.toml
@@ -193,3 +193,4 @@ packages = [
"unzip"
]
install_opts = ["--setopt=install_weak_deps=False"]
+
From b4038dafa900509e4784eb0980aa7e78878d06f4 Mon Sep 17 00:00:00 2001
From: clsty
Date: Fri, 28 Nov 2025 22:42:47 +0800
Subject: [PATCH 025/154] Update dist-nix
- Not use NixGL but let home-manager automatically handle it (since hm 25.11)
- Add libqalculate
---
sdata/dist-nix/README.md | 34 ++++++++++++++++++++--
sdata/dist-nix/home-manager/flake.nix | 19 +++++++-----
sdata/dist-nix/home-manager/home.nix | 19 ++++++++----
sdata/dist-nix/home-manager/quickshell.nix | 10 +++++--
sdata/dist-nix/install-deps.sh | 5 ++--
5 files changed, 67 insertions(+), 20 deletions(-)
diff --git a/sdata/dist-nix/README.md b/sdata/dist-nix/README.md
index 3a8120e04..9aca1d13f 100644
--- a/sdata/dist-nix/README.md
+++ b/sdata/dist-nix/README.md
@@ -37,8 +37,38 @@ As [commented](https://github.com/end-4/dots-hyprland/issues/1061#issuecomment-3
See also [caelestia-dots/shell#668](https://github.com/caelestia-dots/shell/issues/668).
-### NixGL
-On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem.
+### GPU
+On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch.
+
+~~`nixGL` should be used to address the problem.~~
+
+Since home-manager 25.11, for non-NixOS just set the following:
+```nix
+targets.genericLinux.enable = true;
+```
+Then during building, home-manager will show a message to tell you running a command manually to configure GPU, like:
+```bash
+sudo /nix/store/-non-nixos-gpu/bin/non-nixos-gpu-setup
+```
+It runs a bash script with following content:
+```
+#!/nix/store/-bash-/bin/bash
+
+set -e
+
+# Install the systemd service file and ensure that the store path won't be
+# garbage-collected as long as it's installed.
+unit_path=/etc/systemd/system/non-nixos-gpu.service
+ln -sf /nix/store/-non-nixos-gpu/resources/non-nixos-gpu.service "$unit_path"
+ln -sf "$unit_path" "/nix/var/nix"/gcroots/non-nixos-gpu.service
+
+systemctl daemon-reload
+systemctl enable non-nixos-gpu.service
+systemctl restart non-nixos-gpu.service
+```
+_Note: it uses `systemctl`, maybe won't work for OpenRC..._
+
+See [gpu-non-nixos](https://nix-community.github.io/home-manager/index.xhtml#sec-usage-gpu-non-nixos).
# Handling dot files
## Status
diff --git a/sdata/dist-nix/home-manager/flake.nix b/sdata/dist-nix/home-manager/flake.nix
index d88daad6e..97a50c466 100644
--- a/sdata/dist-nix/home-manager/flake.nix
+++ b/sdata/dist-nix/home-manager/flake.nix
@@ -3,23 +3,24 @@
description = "illogical-impulse";
inputs = {
- # Qt 6.10 is not yet available from released version of nixpkgs.
- #nixpkgs.url = "nixpkgs/nixos-25.05";
- nixpkgs.url = "nixpkgs/nixos-unstable";
+ nixpkgs.url = "nixpkgs/nixos-25.11";
+ #nixpkgs.url = "nixpkgs/nixos-unstable";
home-manager = {
- #url = "github:nix-community/home-manager/release-25.05";
- url = "github:nix-community/home-manager/master";
+ url = "github:nix-community/home-manager/release-25.11";
+ #url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
- nixgl.url = "github:nix-community/nixGL";
+ #nixgl.url = "github:nix-community/nixGL";
quickshell = {
url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402";
inputs.nixpkgs.follows = "nixpkgs";
};
};
- outputs = { nixpkgs, home-manager, nixgl, quickshell, ... }:
+ outputs = { nixpkgs, home-manager,
+ #nixgl,
+ quickshell, ... }:
let
home_attrs = rec {
username = import ./username.nix;
@@ -36,7 +37,9 @@
homeConfigurations = {
illogical_impulse = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
- extraSpecialArgs = { inherit home_attrs nixgl quickshell; };
+ extraSpecialArgs = { inherit home_attrs
+ #nixgl
+ quickshell; };
modules = [
./home.nix
];
diff --git a/sdata/dist-nix/home-manager/home.nix b/sdata/dist-nix/home-manager/home.nix
index 596430395..b1381481d 100644
--- a/sdata/dist-nix/home-manager/home.nix
+++ b/sdata/dist-nix/home-manager/home.nix
@@ -1,8 +1,13 @@
-{ config, lib, pkgs, nixgl, quickshell, home_attrs, ... }:
+{ config, lib, pkgs,
+#nixgl,
+quickshell, home_attrs, ... }:
{
programs.home-manager.enable = true;
- nixGL.packages = nixgl.packages;
- nixGL.defaultWrapper = "mesa";
+
+ # Necessary for non-NixOS to handle GPU (since home-manager version 25.11)
+ targets.genericLinux.enable = true;
+ #nixGL.packages = nixgl.packages;
+ #nixGL.defaultWrapper = "mesa";
xdg.portal = {
enable = true;
@@ -27,7 +32,8 @@
systemd.enable = false; plugins = []; settings = {}; extraConfig = "";
enable = true;
## Use NixGL
- package = config.lib.nixGL.wrap pkgs.hyprland;
+ #package = config.lib.nixGL.wrap pkgs.hyprland;
+ package = pkgs.hyprland;
};
home = {
@@ -167,6 +173,7 @@
songrec #songrec
translate-shell #translate-shell
wlogout #wlogout
+ libqalculate #libqalculate
]
++ [
@@ -174,7 +181,9 @@
### illogical-impulse-quickshell-git
#(config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default)
- (import ./quickshell.nix { inherit pkgs quickshell; nixGLWrap = config.lib.nixGL.wrap; })
+ (import ./quickshell.nix { inherit pkgs quickshell;
+ #nixGLWrap = config.lib.nixGL.wrap;
+ })
];
}//home_attrs;
}
diff --git a/sdata/dist-nix/home-manager/quickshell.nix b/sdata/dist-nix/home-manager/quickshell.nix
index 0fb7b57fe..fb81af848 100644
--- a/sdata/dist-nix/home-manager/quickshell.nix
+++ b/sdata/dist-nix/home-manager/quickshell.nix
@@ -1,10 +1,14 @@
-{ pkgs, quickshell, nixGLWrap, ... }:
+{ pkgs, quickshell,
+#nixGLWrap,
+... }:
let
- qs = nixGLWrap quickshell.packages.x86_64-linux.default;
+ #qs = nixGLWrap quickshell.packages.x86_64-linux.default;
+ qs = quickshell.packages.x86_64-linux.default;
in pkgs.stdenv.mkDerivation {
name = "illogical-impulse-quickshell-wrapper";
meta = with pkgs.lib; {
- description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage";
+ #description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage";
+ description = "Quickshell bundled Qt deps for home-manager usage";
license = licenses.gpl3Only;
};
diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh
index 357bb498f..2049efb82 100644
--- a/sdata/dist-nix/install-deps.sh
+++ b/sdata/dist-nix/install-deps.sh
@@ -32,8 +32,8 @@ function install_home-manager(){
try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
command -v $cmd && return
- x nix-channel --add https://nixos.org/channels/nixos-25.05 nixpkgs-home
- x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager
+ x nix-channel --add https://nixos.org/channels/nixos-25.11 nixpkgs-home
+ x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
x nix-channel --update
x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '' -A install
@@ -56,6 +56,7 @@ function hm_deps(){
x home-manager switch --flake .#illogical_impulse \
--extra-experimental-features nix-command \
--extra-experimental-features flakes
+ x sudo /nix/store/*-non-nixos-gpu/bin/non-nixos-gpu-setup
cd $REPO_ROOT
x git rm -f "${SETUP_USERNAME_NIXFILE}"
}
From 533b9c01f53b0e1ec7112057d746013ca4147801 Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Fri, 28 Nov 2025 23:10:33 +0300
Subject: [PATCH 026/154] digital clock: several improvements
---
.../quickshell/ii/modules/common/Config.qml | 5 +
.../modules/common/widgets/ConfigSlider.qml | 42 +++++
.../modules/common/widgets/StyledSlider.qml | 3 +-
.../ii/modules/common/widgets/StyledText.qml | 2 +-
.../ii/background/widgets/clock/ClockText.qml | 18 +++
.../background/widgets/clock/ClockWidget.qml | 43 +-----
.../background/widgets/clock/DigitalClock.qml | 74 +++++++++
.../ii/modules/settings/BackgroundConfig.qml | 146 ++++++++++++------
8 files changed, 246 insertions(+), 87 deletions(-)
create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/ConfigSlider.qml
create mode 100644 dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
create mode 100644 dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index 1716aa2ef..eb62d0955 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -186,7 +186,12 @@ Singleton {
property bool useSineCookie: false
}
property JsonObject digital: JsonObject {
+ property bool adaptiveAlignment: true
+ property bool showDate: true
property bool animateChange: true
+ property bool vertical: false
+ property real weight: 350
+ property real size: 90
}
property JsonObject quote: JsonObject {
property bool enable: false
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ConfigSlider.qml b/dots/.config/quickshell/ii/modules/common/widgets/ConfigSlider.qml
new file mode 100644
index 000000000..b53a5f7c0
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/ConfigSlider.qml
@@ -0,0 +1,42 @@
+import qs.modules.common.widgets
+import qs.modules.common
+import QtQuick
+import QtQuick.Layouts
+
+RowLayout {
+ id: root
+ spacing: 10
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+
+ property string text: ""
+ property string buttonIcon: ""
+ property alias value: slider.value
+ property bool usePercentTooltip: true
+ property real from: slider.from
+ property real to: slider.to
+
+ RowLayout {
+ spacing: 10
+ OptionalMaterialSymbol {
+ id: iconWidget
+ icon: root.buttonIcon
+ iconSize: Appearance.font.pixelSize.larger
+ }
+ StyledText {
+ id: labelWidget
+ text: root.text
+ color: Appearance.colors.colOnSecondaryContainer
+ }
+ }
+
+ StyledSlider {
+ id: slider
+ Layout.fillWidth: true
+ configuration: StyledSlider.Configuration.XS
+ usePercentTooltip: root.usePercentTooltip
+ value: root.value
+ from: root.from
+ to: root.to
+ }
+}
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml
index 98b8eebf3..971a1eb10 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledSlider.qml
@@ -46,7 +46,8 @@ Slider {
property real handleWidth: root.pressed ? handlePressedWidth : handleDefaultWidth
property real handleMargins: 4
property real trackDotSize: 3
- property string tooltipContent: `${Math.round(value * 100)}%`
+ property bool usePercentTooltip: true
+ property string tooltipContent: usePercentTooltip ? `${Math.round(((value - from) / (to - from)) * 100)}%` : `${Math.round(value)}`
property bool wavy: configuration === StyledSlider.Configuration.Wavy // If true, the progress bar will have a wavy fill effect
property bool animateWave: true
property real waveAmplitudeMultiplier: wavy ? 0.5 : 0
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
index 14f6a9c23..f705fc2a4 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
@@ -16,7 +16,7 @@ Text {
hintingPreference: Font.PreferDefaultHinting
family: defaultFont
pixelSize: Appearance?.font.pixelSize.small ?? 15
- variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main
+ //variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main
}
color: Appearance?.m3colors.m3onBackground ?? "black"
linkColor: Appearance?.m3colors.m3primary
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
new file mode 100644
index 000000000..b3f44fbd8
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
@@ -0,0 +1,18 @@
+import qs.modules.common
+import qs.modules.common.widgets
+import QtQuick
+import QtQuick.Layouts
+
+StyledText {
+ Layout.fillWidth: true
+ horizontalAlignment: root.textHorizontalAlignment
+ font {
+ family: Appearance.font.family.expressive
+ pixelSize: 20
+ weight: 350
+ }
+ color: root.colText
+ style: Text.Raised
+ styleColor: Appearance.colors.colShadow
+ animateChange: Config.options.background.widgets.clock.digital.animateChange
+}
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml
index 97e1e468a..82556a3ed 100644
--- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml
@@ -26,7 +26,7 @@ AbstractBackgroundWidget {
visibleWhenLocked: true
property var textHorizontalAlignment: {
- if (root.forceCenter)
+ if (!Config.options.background.widgets.clock.digital.adaptiveAlignment || root.forceCenter)
return Text.AlignHCenter;
if (root.x < root.scaledScreenWidth / 3)
return Text.AlignLeft;
@@ -63,33 +63,7 @@ AbstractBackgroundWidget {
anchors.horizontalCenter: parent.horizontalCenter
shown: root.clockStyle === "digital" && (root.shouldShow)
fade: false
- sourceComponent: ColumnLayout {
- id: clockColumn
- spacing: 6
-
- ClockText {
- font.pixelSize: 90
- text: DateTime.time
- }
- ClockText {
- Layout.topMargin: -5
- text: DateTime.longDate
- }
- StyledText {
- // Somehow gets fucked up if made a ClockText???
- visible: Config.options.background.widgets.clock.quote.enable && Config.options.background.widgets.clock.quote.text.length > 0
- Layout.fillWidth: true
- horizontalAlignment: root.textHorizontalAlignment
- font {
- pixelSize: Appearance.font.pixelSize.normal
- weight: 350
- }
- color: root.colText
- style: Text.Raised
- styleColor: Appearance.colors.colShadow
- text: Config.options.background.widgets.clock.quote.text
- }
- }
+ sourceComponent: DigitalClock {}
}
StatusRow {
anchors.horizontalCenter: parent.horizontalCenter
@@ -154,19 +128,6 @@ AbstractBackgroundWidget {
}
}
- component ClockText: StyledText {
- Layout.fillWidth: true
- horizontalAlignment: root.textHorizontalAlignment
- font {
- family: Appearance.font.family.expressive
- pixelSize: 20
- weight: Font.DemiBold
- }
- color: root.colText
- style: Text.Raised
- styleColor: Appearance.colors.colShadow
- animateChange: Config.options.background.widgets.clock.digital.animateChange
- }
component ClockStatusText: Row {
id: statusTextRow
property alias statusIcon: statusIconWidget.text
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
new file mode 100644
index 000000000..1d4e92f21
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
@@ -0,0 +1,74 @@
+pragma ComponentBehavior: Bound
+
+//TODO: fix imports to only what is necessary
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import QtQuick
+import QtQuick.Layouts
+import Qt5Compat.GraphicalEffects
+import Quickshell.Io
+
+ColumnLayout {
+ id: clockColumn
+ spacing: 6
+
+ property bool isVertical: Config.options.background.widgets.clock.digital.vertical
+
+ Item {
+ Layout.fillWidth: true
+ implicitHeight: timeTextTop.font.pixelSize + (clockColumn.isVertical ? timeTextBottom.font.pixelSize + 10 : 0)
+ implicitWidth: Math.max(timeTextTop.paintedWidth, timeTextBottom.paintedWidth)
+
+ ClockText {
+ id: timeTextTop
+ text: clockColumn.isVertical ? DateTime.time.substring(0, 2) : DateTime.time
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ }
+ font {
+ pixelSize: Config.options.background.widgets.clock.digital.size
+ weight: Config.options.background.widgets.clock.digital.weight
+ }
+ }
+ ClockText {
+ id: timeTextBottom
+ text: clockColumn.isVertical ? DateTime.time.substring(3, 5) : ""
+ visible: clockColumn.isVertical
+
+ anchors {
+ bottom: parent.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+ font {
+ pixelSize: Config.options.background.widgets.clock.digital.size
+ weight: Config.options.background.widgets.clock.digital.weight
+ }
+ }
+ }
+
+ ClockText {
+ visible: Config.options.background.widgets.clock.digital.showDate
+ Layout.topMargin: clockColumn.isVertical ? -10 : 0
+ text: DateTime.longDate
+ }
+ StyledText {
+ // Somehow gets fucked up if made a ClockText???
+ visible: Config.options.background.widgets.clock.quote.enable && Config.options.background.widgets.clock.quote.text.length > 0
+ Layout.fillWidth: true
+ horizontalAlignment: root.textHorizontalAlignment
+ font {
+ pixelSize: Appearance.font.pixelSize.normal
+ weight: 350
+ }
+ color: root.colText
+ style: Text.Raised
+ styleColor: Appearance.colors.colShadow
+ text: Config.options.background.widgets.clock.quote.text
+ }
+}
+
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
index 66630cc24..18c30853e 100644
--- a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
+++ b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
@@ -120,48 +120,52 @@ ContentPage {
}
}
- ContentSubsection {
- visible: !Config.options.background.widgets.clock.showOnlyWhenLocked
- title: Translation.tr("Clock style")
- ConfigSelectionArray {
- currentValue: Config.options.background.widgets.clock.style
- onSelected: newValue => {
- Config.options.background.widgets.clock.style = newValue;
- }
- options: [
- {
- displayName: Translation.tr("Digital"),
- icon: "timer_10",
- value: "digital"
- },
- {
- displayName: Translation.tr("Cookie"),
- icon: "cookie",
- value: "cookie"
+ ConfigRow {
+ ContentSubsection {
+ visible: !Config.options.background.widgets.clock.showOnlyWhenLocked
+ title: Translation.tr("Clock style")
+ Layout.fillWidth: true
+ ConfigSelectionArray {
+ currentValue: Config.options.background.widgets.clock.style
+ onSelected: newValue => {
+ Config.options.background.widgets.clock.style = newValue;
}
- ]
+ options: [
+ {
+ displayName: Translation.tr("Digital"),
+ icon: "timer_10",
+ value: "digital"
+ },
+ {
+ displayName: Translation.tr("Cookie"),
+ icon: "cookie",
+ value: "cookie"
+ }
+ ]
+ }
}
- }
- ContentSubsection {
- title: Translation.tr("Clock style (locked)")
- ConfigSelectionArray {
- currentValue: Config.options.background.widgets.clock.styleLocked
- onSelected: newValue => {
- Config.options.background.widgets.clock.styleLocked = newValue;
- }
- options: [
- {
- displayName: Translation.tr("Digital"),
- icon: "timer_10",
- value: "digital"
- },
- {
- displayName: Translation.tr("Cookie"),
- icon: "cookie",
- value: "cookie"
+ ContentSubsection {
+ title: Translation.tr("Clock style (locked)")
+ Layout.fillWidth: false
+ ConfigSelectionArray {
+ currentValue: Config.options.background.widgets.clock.styleLocked
+ onSelected: newValue => {
+ Config.options.background.widgets.clock.styleLocked = newValue;
}
- ]
+ options: [
+ {
+ displayName: Translation.tr("Digital"),
+ icon: "timer_10",
+ value: "digital"
+ },
+ {
+ displayName: Translation.tr("Cookie"),
+ icon: "cookie",
+ value: "cookie"
+ }
+ ]
+ }
}
}
@@ -169,12 +173,66 @@ ContentPage {
visible: settingsClock.digitalPresent
title: Translation.tr("Digital clock settings")
- ConfigSwitch {
- buttonIcon: "animation"
- text: Translation.tr("Animate time change")
- checked: Config.options.background.widgets.clock.digital.animateChange
- onCheckedChanged: {
- Config.options.background.widgets.clock.digital.animateChange = checked;
+ ConfigRow {
+ ConfigSwitch {
+ buttonIcon: "vertical_distribute"
+ text: Translation.tr("Vertical")
+ checked: Config.options.background.widgets.clock.digital.vertical
+ onCheckedChanged: {
+ Config.options.background.widgets.clock.digital.vertical = checked;
+ }
+ }
+ ConfigSwitch {
+ buttonIcon: "animation"
+ text: Translation.tr("Animate time change")
+ checked: Config.options.background.widgets.clock.digital.animateChange
+ onCheckedChanged: {
+ Config.options.background.widgets.clock.digital.animateChange = checked;
+ }
+ }
+ }
+
+ ConfigRow {
+ ConfigSwitch {
+ buttonIcon: "date_range"
+ text: Translation.tr("Show date")
+ checked: Config.options.background.widgets.clock.digital.showDate
+ onCheckedChanged: {
+ Config.options.background.widgets.clock.digital.showDate = checked;
+ }
+ }
+ ConfigSwitch {
+ buttonIcon: "activity_zone"
+ text: Translation.tr("Use adaptive alignment")
+ checked: Config.options.background.widgets.clock.digital.adaptiveAlignment
+ onCheckedChanged: {
+ Config.options.background.widgets.clock.digital.adaptiveAlignment = checked;
+ }
+ StyledToolTip {
+ text: Translation.tr("Aligns the date and quote to left, center or right depending on its position on the screen.")
+ }
+ }
+ }
+ ConfigSlider {
+ text: Translation.tr("Font weight")
+ value: Config.options.background.widgets.clock.digital.weight
+ usePercentTooltip: false
+ buttonIcon: "format_bold"
+ from: 1
+ to: 1000
+ onValueChanged: {
+ Config.options.background.widgets.clock.digital.weight = value;
+ }
+ }
+ ConfigSlider {
+ text: Translation.tr("Font Size")
+ value: Config.options.background.widgets.clock.digital.size
+ usePercentTooltip: false
+ buttonIcon: "format_size"
+ from: 70
+ to: 150
+ onValueChanged: {
+ Config.options.background.widgets.clock.digital.size = value;
}
}
}
From fd209851d94378205c65e11d54db8a86d8169195 Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Fri, 28 Nov 2025 23:21:58 +0300
Subject: [PATCH 027/154] digital clock: use clocktext instead of styledtext
---
.../ii/modules/common/widgets/StyledText.qml | 2 +-
.../ii/background/widgets/clock/DigitalClock.qml | 14 +++-----------
2 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
index f705fc2a4..db6df827c 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
@@ -16,7 +16,7 @@ Text {
hintingPreference: Font.PreferDefaultHinting
family: defaultFont
pixelSize: Appearance?.font.pixelSize.small ?? 15
- //variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main
+ //variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main // Disabled for now because it causes some fonts to not display their weight properly
}
color: Appearance?.m3colors.m3onBackground ?? "black"
linkColor: Appearance?.m3colors.m3primary
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
index 1d4e92f21..ac94d254f 100644
--- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
@@ -54,19 +54,11 @@ ColumnLayout {
Layout.topMargin: clockColumn.isVertical ? -10 : 0
text: DateTime.longDate
}
- StyledText {
- // Somehow gets fucked up if made a ClockText???
+ ClockText {
visible: Config.options.background.widgets.clock.quote.enable && Config.options.background.widgets.clock.quote.text.length > 0
- Layout.fillWidth: true
- horizontalAlignment: root.textHorizontalAlignment
- font {
- pixelSize: Appearance.font.pixelSize.normal
- weight: 350
- }
- color: root.colText
- style: Text.Raised
- styleColor: Appearance.colors.colShadow
+ font.pixelSize: Appearance.font.pixelSize.normal
text: Config.options.background.widgets.clock.quote.text
+ animateChange: false
}
}
From 21f2a9c65d228a457d3038ce526040f24c7de279 Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Fri, 28 Nov 2025 23:48:06 +0300
Subject: [PATCH 028/154] fix: find a better solution on variableAxes
---
.../.config/quickshell/ii/modules/common/widgets/StyledText.qml | 2 +-
.../ii/modules/ii/background/widgets/clock/ClockText.qml | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
index db6df827c..14f6a9c23 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledText.qml
@@ -16,7 +16,7 @@ Text {
hintingPreference: Font.PreferDefaultHinting
family: defaultFont
pixelSize: Appearance?.font.pixelSize.small ?? 15
- //variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main // Disabled for now because it causes some fonts to not display their weight properly
+ variableAxes: shouldUseNumberFont ? ({}) : Appearance.font.variableAxes.main
}
color: Appearance?.m3colors.m3onBackground ?? "black"
linkColor: Appearance?.m3colors.m3primary
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
index b3f44fbd8..d16103ed7 100644
--- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
@@ -10,6 +10,7 @@ StyledText {
family: Appearance.font.family.expressive
pixelSize: 20
weight: 350
+ variableAxes: ({})
}
color: root.colText
style: Text.Raised
From 6b90e37b0f16678bd90858e3339b03161996849a Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sat, 29 Nov 2025 00:23:19 +0100
Subject: [PATCH 029/154] waffles: expandable notifs
---
.../ii/modules/waffle/bar/BarButton.qml | 29 +----
.../ii/modules/waffle/looks/AcrylicButton.qml | 42 +++++++
.../modules/waffle/looks/AcrylicRectangle.qml | 9 +-
.../ii/modules/waffle/looks/Looks.qml | 3 +
.../ii/modules/waffle/looks/WText.qml | 3 +
.../NotificationHeaderButton.qml | 18 ++-
.../SmallBorderedIconAndTextButton.qml | 11 +-
.../notificationCenter/WNotificationGroup.qml | 14 ++-
.../WSingleNotification.qml | 106 ++++++++++++++++--
9 files changed, 185 insertions(+), 50 deletions(-)
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml
index 53a37cba0..4502b22f7 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml
@@ -5,17 +5,12 @@ import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
-WButton {
+AcrylicButton {
id: root
property var altAction: () => {}
property var middleClickAction: () => {}
- colBackground: ColorUtils.transparentize(Looks.colors.bg1)
- colBackgroundHover: Looks.colors.bg1Hover
- colBackgroundActive: Looks.colors.bg1Active
- property color colBackgroundBorder
- property color color
Layout.fillHeight: true
topInset: 4
bottomInset: 4
@@ -23,16 +18,7 @@ WButton {
rightInset: 0
horizontalPadding: 8
- colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.backgroundTransparency : 1)
- color: {
- if (root.down) {
- return root.colBackgroundActive
- } else if ((root.hovered && !root.down) || root.checked) {
- return root.colBackgroundHover
- } else {
- return root.colBackground
- }
- }
+ colBackground: ColorUtils.transparentize(Looks.colors.bg1)
MouseArea {
anchors.fill: parent
@@ -50,15 +36,4 @@ WButton {
}
}
- background: AcrylicRectangle {
- shiny: ((root.hovered && !root.down) || root.checked)
- color: root.color
- radius: Looks.radius.medium
- border.width: 1
- border.color: root.colBackgroundBorder
-
- Behavior on border.color {
- animation: Looks.transition.color.createObject(this)
- }
- }
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml
new file mode 100644
index 000000000..ef5c0747a
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml
@@ -0,0 +1,42 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+WButton {
+ id: root
+
+ colBackground: Looks.colors.bg1
+ colBackgroundHover: Looks.colors.bg1Hover
+ colBackgroundActive: Looks.colors.bg1Active
+ property color colBackgroundBorder
+ property color color
+ property alias border: background.border
+ property alias shinyColor: background.borderColor
+
+ colBackgroundBorder: ColorUtils.transparentize(color, (root.checked || root.hovered) ? Looks.backgroundTransparency : 0)
+ color: {
+ if (root.down) {
+ return root.colBackgroundActive
+ } else if ((root.hovered && !root.down) || root.checked) {
+ return root.colBackgroundHover
+ } else {
+ return root.colBackground
+ }
+ }
+
+ background: AcrylicRectangle {
+ id: background
+ shiny: ((root.hovered && !root.down) || root.checked)
+ color: root.color
+ radius: Looks.radius.medium
+ border.width: 1
+ border.color: root.colBackgroundBorder
+
+ Behavior on border.color {
+ animation: Looks.transition.color.createObject(this)
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml
index 7e041d111..7fecaa068 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml
@@ -9,16 +9,17 @@ Rectangle {
id: root
property bool shiny: true // Top border
- property color borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, shiny ? 0.5 : 1)
+ property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Hover, 0.7)
+ property color internalBorderColor: ColorUtils.transparentize(borderColor, shiny ? 0.0 : 1)
color: Looks.colors.bg1Hover
radius: Looks.radius.medium
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
- Behavior on borderColor {
+ Behavior on internalBorderColor {
animation: Looks.transition.color.createObject(this)
}
- onBorderColorChanged: {
+ onInternalBorderColorChanged: {
borderCanvas.requestPaint();
}
@@ -32,7 +33,7 @@ Rectangle {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
- var borderColor = root.borderColor;
+ var borderColor = root.internalBorderColor;
var r = root.radius;
var fadeLength = Math.max(1, r);
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
index e55f840cb..a321fa98e 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
@@ -53,6 +53,7 @@ Singleton {
property color controlBgHover: '#57575B'
property color controlFg: "#FFFFFF"
property color accentUnfocused: "#848484"
+ property color link: "#235CCF"
}
darkColors: QtObject {
id: darkColors
@@ -80,6 +81,7 @@ Singleton {
property color controlBgHover: "#CFCED1"
property color controlFg: "#454545"
property color accentUnfocused: "#989898"
+ property color link: "#A7C9FC"
}
colors: QtObject {
id: colors
@@ -110,6 +112,7 @@ Singleton {
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
+ property color link: root.dark ? root.darkColors.link : root.lightColors.link
property color danger: "#C42B1C"
property color dangerActive: "#B62D1F"
property color warning: "#FF9900"
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml
index 240fd63be..0da156893 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml
@@ -8,8 +8,11 @@ Text {
color: Looks.colors.fg
font {
+ hintingPreference: Font.PreferFullHinting
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular
}
+
+ linkColor: Looks.colors.link
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
index 860451fc3..9aa20a690 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml
@@ -8,18 +8,24 @@ import qs.modules.common.functions
import qs.modules.waffle.looks
WBorderlessButton {
- id: headerButton
+ id: root
Layout.fillWidth: false
- implicitWidth: 16
- implicitHeight: 16
+ property real implicitSize: 16
+ implicitWidth: implicitSize
+ implicitHeight: implicitSize
color: "transparent"
+ colForeground: root.hovered && !root.pressed ? Looks.colors.fg : Looks.colors.fg1
+
+ Behavior on colForeground {
+ animation: Looks.transition.color.createObject(this)
+ }
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
- implicitSize: 16
- icon: headerButton.icon.name
- color: headerButton.hovered && !headerButton.pressed ? Looks.colors.fg : Looks.colors.fg1
+ implicitSize: root.implicitSize
+ icon: root.icon.name
+ color: root.colForeground
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
index c4331a7dc..faab4d90d 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml
@@ -2,18 +2,27 @@ import QtQuick
import qs
import qs.services
import qs.modules.common
+import qs.modules.common.functions
import qs.modules.waffle.looks
-SmallBorderedIconButton {
+AcrylicButton {
id: root
property bool iconVisible: true
property string iconName: ""
property bool iconFilled: true
+ colBackground: Looks.colors.bg2
+ colBackgroundHover: Looks.colors.bg2Hover
+ colBackgroundActive: Looks.colors.bg2Active
+ property color colBorder: Looks.colors.bg2Border
+ property color colBorderToggled: Looks.colors.accent
+ border.color: checked ? colBorderToggled : colBorder
+
leftPadding: 12
rightPadding: 12
implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
+ implicitHeight: 24
contentItem: Row {
id: focusButtonContent
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
index 837c7c016..21ef2c544 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
@@ -12,6 +12,7 @@ MouseArea {
required property var notificationGroup
readonly property var notifications: notificationGroup?.notifications ?? []
+ property bool expanded: false
implicitWidth: contentLayout.implicitWidth
implicitHeight: contentLayout.implicitHeight
@@ -34,12 +35,23 @@ MouseArea {
interactive: false
spacing: 4
model: ScriptModel {
- values: root.notifications.slice().reverse()
+ values: root.expanded ? root.notifications.slice().reverse() : root.notifications.slice(-1)
+ objectProp: "notificationId"
}
delegate: WSingleNotification {
+ required property int index
required property var modelData
width: ListView.view.width
notification: modelData
+ groupExpandControlMessage: {
+ if (root.notifications.length === 0) return "";
+ if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1);
+ if (index === root.notifications.length - 1) return Translation.tr("See fewer");
+ return "";
+ }
+ onGroupExpandToggle: {
+ root.expanded = !root.expanded;
+ }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
index 42a832adb..95780133c 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
@@ -13,10 +13,17 @@ MouseArea {
required property var notification
property bool expanded: false
+ property string groupExpandControlMessage: ""
+ signal groupExpandToggle
+ hoverEnabled: true
implicitHeight: contentItem.implicitHeight
implicitWidth: contentItem.implicitWidth
+ Behavior on implicitHeight {
+ animation: Looks.transition.enter.createObject(this)
+ }
+
Rectangle {
id: contentItem
anchors.fill: parent
@@ -26,32 +33,109 @@ MouseArea {
implicitHeight: notificationContent.implicitHeight + padding * 2
implicitWidth: notificationContent.implicitWidth + padding * 2
border.width: 1
- border.color: Looks.applyContentTransparency(Looks.colors.ambientShadow)
+ border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1)
ColumnLayout {
id: notificationContent
anchors.fill: parent
anchors.margins: contentItem.padding
+ spacing: 19
RowLayout {
Layout.fillWidth: true
- WText {
- text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
+
+ ExpandButton {
+ Layout.topMargin: -2
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ NotificationHeaderButton {
+ Layout.rightMargin: 4
+ opacity: root.containsMouse ? 1 : 0
+ icon.name: "dismiss"
+ implicitSize: 12
+ onClicked: {
+ Qt.callLater(() => {
+ Notifications.discardNotification(root.notification?.notificationId);
+ });
+ }
}
}
ColumnLayout {
Layout.fillWidth: true
- WText {
- Layout.fillWidth: true
- elide: Text.ElideRight
- text: root.notification.summary
+ spacing: 3
+
+ SummaryText {}
+ BodyText {}
+ }
+
+ AcrylicButton {
+ id: groupExpandButton
+ visible: root.groupExpandControlMessage !== ""
+ Layout.bottomMargin: 2
+ horizontalPadding: 10
+ implicitHeight: 24
+ implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
+ onClicked: root.groupExpandToggle()
+ contentItem: Item {
+ WText {
+ id: expandButtonText
+ anchors.centerIn: parent
+ text: root.groupExpandControlMessage
+ }
}
+ }
+ }
+ }
+
+ component SummaryText: WText {
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ text: root.notification?.summary
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+
+ component BodyText: WText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignTop
+ wrapMode: Text.Wrap
+ maximumLineCount: root.expanded ? 100 : 1
+ text: root.notification?.body
+ color: Looks.colors.subfg
+ }
+
+ component ExpandButton: NotificationHeaderButton {
+ id: expandButton
+ implicitWidth: expandButtonContent.implicitWidth
+ onClicked: root.expanded = !root.expanded
+
+ contentItem: Item {
+ id: expandButtonContent
+ implicitWidth: expandButtonRow.implicitWidth
+ implicitHeight: expandButtonRow.implicitHeight
+ RowLayout {
+ id: expandButtonRow
+ anchors.centerIn: parent
+ spacing: 8
WText {
- Layout.fillWidth: true
- elide: Text.ElideRight
- wrapMode: Text.Wrap
- maximumLineCount: root.expanded ? 100 : 1
+ color: expandButton.colForeground
+ text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
+ }
+ FluentIcon {
+ Layout.rightMargin: 12
+ icon: "chevron-down"
+ implicitSize: 18
+ rotation: root.expanded ? -180 : 0
+ color: expandButton.colForeground
+ Behavior on rotation {
+ animation: Looks.transition.rotate.createObject(this)
+ }
}
}
}
From d2c019f8de66e1cbd268878e626c4d1f3a237241 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sat, 29 Nov 2025 00:37:15 +0100
Subject: [PATCH 030/154] fix "+0 notifications"
---
.../ii/modules/waffle/notificationCenter/WNotificationGroup.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
index 21ef2c544..122469771 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml
@@ -44,7 +44,7 @@ MouseArea {
width: ListView.view.width
notification: modelData
groupExpandControlMessage: {
- if (root.notifications.length === 0) return "";
+ if (root.notifications.length <= 1) return "";
if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1);
if (index === root.notifications.length - 1) return Translation.tr("See fewer");
return "";
From 3cf14671ad5ffcb984c1e176e5839b2ca885f8fe Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Sat, 29 Nov 2025 02:40:28 +0300
Subject: [PATCH 031/154] fix: get gif size properly
---
.../modules/common/utils/ImageDownloaderProcess.qml | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml b/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml
index 11ff92a6d..3a86b2fe1 100644
--- a/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml
+++ b/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml
@@ -18,14 +18,19 @@ Process {
running: true
command: ["bash", "-c",
- `mkdir -p $(dirname '${processFilePath(filePath)}'); [ -f '${processFilePath(filePath)}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath(filePath)}' && magick identify -format '%w %h' '${processFilePath(filePath)}'[0]`
+ `mkdir -p $(dirname '${processFilePath()}'); [ -f '${processFilePath()}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath()}' && file '${processFilePath()}'`
]
stdout: StdioCollector {
id: imageSizeOutputCollector
onStreamFinished: {
const output = imageSizeOutputCollector.text.trim();
- const [width, height] = output.split(" ").map(Number);
- root.done(root.filePath, width, height);
+ const match = output.match(/(\d+)\s*x\s*(\d+)/);
+
+ if (match) {
+ const width = Number(match[1]);
+ const height = Number(match[2]);
+ root.done(root.filePath, width, height);
+ }
}
}
}
From c11814b1f8a9a5bd54fdfdd360628386c6c6c1f7 Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Sat, 29 Nov 2025 14:35:52 +0300
Subject: [PATCH 032/154] fix: weight property not properly applied (styleName
conflict)
---
.../ii/modules/ii/background/widgets/clock/ClockText.qml | 1 +
1 file changed, 1 insertion(+)
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
index d16103ed7..39267b83d 100644
--- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockText.qml
@@ -11,6 +11,7 @@ StyledText {
pixelSize: 20
weight: 350
variableAxes: ({})
+ styleName: ""
}
color: root.colText
style: Text.Raised
From 677fa06b06934174109e00206b2661ed2d686468 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sat, 29 Nov 2025 12:51:31 +0100
Subject: [PATCH 033/154] waffles: notifications: image support
---
.../common/functions/NotificationUtils.qml | 24 +++
.../common/widgets/NotificationItem.qml | 31 +---
.../ii/modules/waffle/bar/StartButton.qml | 1 +
.../NotificationCenterContent.qml | 19 ++-
.../WSingleNotification.qml | 157 ++++++++++++++----
5 files changed, 172 insertions(+), 60 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
index 8a336e8ad..d6adcc0f6 100644
--- a/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
+++ b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml
@@ -84,4 +84,28 @@ Singleton {
// Older dates
return Qt.formatDateTime(messageTime, "MMMM dd");
}
+
+ function processNotificationBody(body, appName) {
+ let processedBody = body
+
+ // Clean Chromium-based browsers notifications - remove first line
+ if (appName) {
+ const lowerApp = appName.toLowerCase()
+ const chromiumBrowsers = [
+ "brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
+ ]
+
+ if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
+ const lines = body.split('\n\n')
+
+ if (lines.length > 1 && lines[0].startsWith(' lowerApp.includes(name))) {
- const lines = body.split('\n\n')
-
- if (lines.length > 1 && lines[0].startsWith('")
+ return NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
")
}
}
}
ColumnLayout { // Expanded content
+ id: expandedContentColumn
Layout.fillWidth: true
opacity: root.expanded ? 1 : 0
visible: opacity > 0
@@ -218,8 +197,8 @@ Item { // Notification item area
elide: Text.ElideRight
textFormat: Text.RichText
text: {
- return `` +
- `${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
")}`
+ return `` +
+ `${NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
")}`
}
onLinkActivated: (link) => {
@@ -293,6 +272,8 @@ Item { // Notification item area
id: actionRepeater
model: notificationObject.actions
NotificationActionButton {
+ id: notifAction
+ required property var modelData
Layout.fillWidth: true
buttonText: modelData.text
urgency: notificationObject.urgency
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
index f4a15cc00..5ec96eeb4 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
@@ -7,6 +7,7 @@ import qs.services
import qs.modules.common
import qs.modules.waffle.looks
+// TODO: Replace the icon with QMLized svg (with /usr/lib/qt6/bin/svgtoqml) for proper micro-animation
AppButton {
id: root
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
index 797cee28a..47ad2f92d 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -20,6 +20,7 @@ WBarAttachedPanelContent {
property bool collapsed: false
contentItem: ColumnLayout {
+ id: contentLayout
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
@@ -41,9 +42,24 @@ WBarAttachedPanelContent {
}
contentItem: NotificationPaneContent {
implicitWidth: calendarColumnLayout.implicitWidth
- implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230
+ implicitHeight: {
+ if (Notifications.list.length > 0) {
+ return ((contentLayout.height - calendarPane.height - contentLayout.spacing) - notificationPane.borderWidth * 2)
+ }
+ return 230;
+ }
+ Timer {
+ id: enableTimer
+ interval: Config.options.hacks.arbitraryRaceConditionDelay
+ onTriggered: heightBehavior.enabled = true;
+ }
Behavior on implicitHeight {
+ id: heightBehavior
+ enabled: false
+ Component.onCompleted: {
+ enableTimer.restart();
+ }
animation: Looks.transition.enter.createObject(this)
}
}
@@ -51,6 +67,7 @@ WBarAttachedPanelContent {
}
WPane {
+ id: calendarPane
contentItem: ColumnLayout {
id: calendarColumnLayout
spacing: 0
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
index 95780133c..856ddb160 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
@@ -1,3 +1,4 @@
+pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
@@ -41,52 +42,115 @@ MouseArea {
anchors.margins: contentItem.padding
spacing: 19
- RowLayout {
+ // Header
+ SingleNotificationHeader {
Layout.fillWidth: true
+ }
- ExpandButton {
- Layout.topMargin: -2
+ // Content
+ Item {
+ id: actualContent
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ property real spacing: 16
+ implicitHeight: Math.max(contentColumn.implicitHeight, imageLoader.height)
+ implicitWidth: contentColumn.implicitWidth
+
+ Loader {
+ id: imageLoader
+ active: root.notification.image != ""
+ sourceComponent: StyledImage {
+ width: 48
+ height: 48
+ sourceSize.width: width
+ sourceSize.height: height
+ source: root.notification.image
+ }
}
- Item {
- Layout.fillWidth: true
- }
+ ColumnLayout {
+ id: contentColumn
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ spacing: 3
- NotificationHeaderButton {
- Layout.rightMargin: 4
- opacity: root.containsMouse ? 1 : 0
- icon.name: "dismiss"
- implicitSize: 12
- onClicked: {
- Qt.callLater(() => {
- Notifications.discardNotification(root.notification?.notificationId);
- });
+ SummaryText {
+ id: summaryText
+ Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
+ }
+ BodyText {
+ Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
+ // onLineLaidOut: (line) => {
+ // if (!imageLoader.active) return;
+ // const dodgeDistance = imageLoader.width + actualContent.spacing;
+ // // print(line.y, dodgeDistance)
+ // if (summaryText.height + line.y > dodgeDistance) {
+ // line.x -= dodgeDistance;
+ // line.width += dodgeDistance;
+ // }
+ // }
}
}
}
- ColumnLayout {
+ // Actions
+ ActionsRow {
Layout.fillWidth: true
- spacing: 3
-
- SummaryText {}
- BodyText {}
}
- AcrylicButton {
- id: groupExpandButton
- visible: root.groupExpandControlMessage !== ""
+ // "+1 notifications" button
+ GroupExpandButton {
Layout.bottomMargin: 2
- horizontalPadding: 10
- implicitHeight: 24
- implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
- onClicked: root.groupExpandToggle()
- contentItem: Item {
- WText {
- id: expandButtonText
- anchors.centerIn: parent
- text: root.groupExpandControlMessage
- }
+ }
+ }
+ }
+
+ component SingleNotificationHeader: RowLayout {
+ ExpandButton {
+ Layout.topMargin: -2
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ NotificationHeaderButton {
+ Layout.rightMargin: 4
+ opacity: root.containsMouse ? 1 : 0
+ icon.name: "dismiss"
+ implicitSize: 12
+ onClicked: {
+ Qt.callLater(() => {
+ Notifications.discardNotification(root.notification?.notificationId);
+ });
+ }
+ }
+ }
+
+ component ActionsRow: RowLayout {
+ visible: root.expanded && root.notification.actions.length > 0
+ uniformCellSizes: true
+ Repeater {
+ id: actionRepeater
+ model: root.notification.actions
+ delegate: WBorderedButton {
+ id: actionButton
+ Layout.fillHeight: true
+ required property var modelData
+ Layout.fillWidth: true
+ verticalPadding: 16
+ horizontalPadding: 12
+ text: modelData.text
+ implicitHeight: actionButtonText.implicitHeight + verticalPadding * 2
+ contentItem: WText {
+ id: actionButtonText
+ text: actionButton.text
+ font.pixelSize: Looks.font.pixelSize.large
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.Wrap
}
}
}
@@ -106,8 +170,17 @@ MouseArea {
verticalAlignment: Text.AlignTop
wrapMode: Text.Wrap
maximumLineCount: root.expanded ? 100 : 1
- text: root.notification?.body
+ text: {
+ if (root.expanded)
+ return `` + `${NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "
")}`;
+ return NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "
");
+ }
color: Looks.colors.subfg
+ textFormat: root.expanded ? Text.RichText : Text.StyledText
+ onLinkActivated: link => {
+ Qt.openUrlExternally(link);
+ GlobalStates.sidebarRightOpen = false;
+ }
}
component ExpandButton: NotificationHeaderButton {
@@ -140,4 +213,20 @@ MouseArea {
}
}
}
+
+ component GroupExpandButton: AcrylicButton {
+ id: groupExpandButton
+ visible: root.groupExpandControlMessage !== ""
+ horizontalPadding: 10
+ implicitHeight: 24
+ implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
+ onClicked: root.groupExpandToggle()
+ contentItem: Item {
+ WText {
+ id: expandButtonText
+ anchors.centerIn: parent
+ text: root.groupExpandControlMessage
+ }
+ }
+ }
}
From 889298287423dc3469d967142c02b3968b2694c7 Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Sat, 29 Nov 2025 14:57:38 +0300
Subject: [PATCH 034/154] feat: refactor font settings and add width config
option
---
.../quickshell/ii/modules/common/Config.qml | 7 +++++--
.../background/widgets/clock/DigitalClock.qml | 14 ++++++++++----
.../ii/modules/settings/BackgroundConfig.qml | 19 +++++++++++++++----
3 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index eb62d0955..89169fbdf 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -190,8 +190,11 @@ Singleton {
property bool showDate: true
property bool animateChange: true
property bool vertical: false
- property real weight: 350
- property real size: 90
+ property JsonObject font: JsonObject {
+ property real weight: 350
+ property real width: 100
+ property real size: 90
+ }
}
property JsonObject quote: JsonObject {
property bool enable: false
diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
index ac94d254f..90a65a0dd 100644
--- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
+++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/DigitalClock.qml
@@ -29,8 +29,11 @@ ColumnLayout {
horizontalCenter: parent.horizontalCenter
}
font {
- pixelSize: Config.options.background.widgets.clock.digital.size
- weight: Config.options.background.widgets.clock.digital.weight
+ pixelSize: Config.options.background.widgets.clock.digital.font.size
+ weight: Config.options.background.widgets.clock.digital.font.weight
+ variableAxes: ({
+ "wdth": Config.options.background.widgets.clock.digital.font.width,
+ })
}
}
ClockText {
@@ -43,8 +46,11 @@ ColumnLayout {
horizontalCenter: parent.horizontalCenter
}
font {
- pixelSize: Config.options.background.widgets.clock.digital.size
- weight: Config.options.background.widgets.clock.digital.weight
+ pixelSize: Config.options.background.widgets.clock.digital.font.size
+ weight: Config.options.background.widgets.clock.digital.font.weight
+ variableAxes: ({
+ "wdth": Config.options.background.widgets.clock.digital.font.width,
+ })
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
index 18c30853e..bb08ccb0c 100644
--- a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
+++ b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
@@ -215,24 +215,35 @@ ContentPage {
}
ConfigSlider {
text: Translation.tr("Font weight")
- value: Config.options.background.widgets.clock.digital.weight
+ value: Config.options.background.widgets.clock.digital.font.weight
usePercentTooltip: false
buttonIcon: "format_bold"
from: 1
to: 1000
onValueChanged: {
- Config.options.background.widgets.clock.digital.weight = value;
+ Config.options.background.widgets.clock.digital.font.weight = value;
+ }
+ }
+ ConfigSlider {
+ text: Translation.tr("Font Width")
+ value: Config.options.background.widgets.clock.digital.font.width
+ usePercentTooltip: false
+ buttonIcon: "fit_width"
+ from: 25
+ to: 125
+ onValueChanged: {
+ Config.options.background.widgets.clock.digital.font.width = value;
}
}
ConfigSlider {
text: Translation.tr("Font Size")
- value: Config.options.background.widgets.clock.digital.size
+ value: Config.options.background.widgets.clock.digital.font.size
usePercentTooltip: false
buttonIcon: "format_size"
from: 70
to: 150
onValueChanged: {
- Config.options.background.widgets.clock.digital.size = value;
+ Config.options.background.widgets.clock.digital.font.size = value;
}
}
}
From f5fea85334b738186d75bd680b94e44f9ec6439e Mon Sep 17 00:00:00 2001
From: vaguesyntax
Date: Sat, 29 Nov 2025 15:05:07 +0300
Subject: [PATCH 035/154] fix: capital letters
---
.../quickshell/ii/modules/settings/BackgroundConfig.qml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
index bb08ccb0c..eddc06fa9 100644
--- a/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
+++ b/dots/.config/quickshell/ii/modules/settings/BackgroundConfig.qml
@@ -225,7 +225,7 @@ ContentPage {
}
}
ConfigSlider {
- text: Translation.tr("Font Width")
+ text: Translation.tr("Font width")
value: Config.options.background.widgets.clock.digital.font.width
usePercentTooltip: false
buttonIcon: "fit_width"
@@ -236,7 +236,7 @@ ContentPage {
}
}
ConfigSlider {
- text: Translation.tr("Font Size")
+ text: Translation.tr("Font size")
value: Config.options.background.widgets.clock.digital.font.size
usePercentTooltip: false
buttonIcon: "format_size"
From 44422004791e8d651bf3094bfb6d51e7f1dee737 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Sat, 29 Nov 2025 23:23:58 +0100
Subject: [PATCH 036/154] waffles: start menu base
---
dots/.config/hypr/hyprland/keybinds.conf | 32 ++---
dots/.config/quickshell/ii/GlobalStates.qml | 1 +
.../ii/assets/icons/fluent/power-filled.svg | 4 +
.../ii/assets/icons/fluent/power.svg | 4 +
.../fluent/system-search-checked-dark.svg | 14 +--
.../fluent/system-search-checked-light.svg | 16 +--
.../ii/modules/common/Directories.qml | 4 +
.../ii/modules/common/widgets/StyledImage.qml | 10 ++
.../modules/common/widgets/StyledToolTip.qml | 1 +
.../ii/modules/ii/overview/Overview.qml | 22 ++--
.../ii/modules/waffle/bar/AppButton.qml | 2 +-
.../ii/modules/waffle/bar/StartButton.qml | 3 +-
.../ii/modules/waffle/bar/WidgetsButton.qml | 2 +-
.../waffle/bar/tasks/WindowPreview.qml | 2 +-
.../ii/modules/waffle/looks/Looks.qml | 6 +-
.../{bar/AppIcon.qml => looks/WAppIcon.qml} | 1 -
.../ii/modules/waffle/looks/WButton.qml | 3 +-
.../ii/modules/waffle/looks/WTextInput.qml | 18 +++
.../NotificationCenterContent.qml | 3 +-
.../WSingleNotification.qml | 16 ++-
.../ii/modules/waffle/startMenu/SearchBar.qml | 84 +++++++++++++
.../waffle/startMenu/SearchPageContent.qml | 16 +++
.../waffle/startMenu/StartMenuContent.qml | 39 ++++++
.../waffle/startMenu/StartPageContent.qml | 98 +++++++++++++++
.../waffle/startMenu/WaffleStartMenu.qml | 119 ++++++++++++++++++
dots/.config/quickshell/ii/shell.qml | 5 +-
26 files changed, 464 insertions(+), 61 deletions(-)
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/power.svg
rename dots/.config/quickshell/ii/modules/waffle/{bar/AppIcon.qml => looks/WAppIcon.qml} (94%)
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml
diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf
index 020fe582d..6032ab65a 100644
--- a/dots/.config/hypr/hyprland/keybinds.conf
+++ b/dots/.config/hypr/hyprland/keybinds.conf
@@ -4,27 +4,27 @@
#!
##! Shell
# These absolutely need to be on top, or they won't work consistently
-bindid = Super, Super_L, Toggle overview, global, quickshell:overviewToggleRelease # Toggle overview/launcher
-bindid = Super, Super_R, Toggle overview, global, quickshell:overviewToggleRelease # [hidden] Toggle overview/launcher
+bindid = Super, Super_L, Toggle search, global, quickshell:searchToggleRelease # Toggle search
+bindid = Super, Super_R, Toggle search, global, quickshell:searchToggleRelease # [hidden] Toggle search
bind = Super, Super_L, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
bind = Super, Super_R, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
-binditn = Super, catchall, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Ctrl, Super_L, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Ctrl, Super_R, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:272, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:273, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:274, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:275, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:276, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse:277, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse_up, global, quickshell:overviewToggleReleaseInterrupt # [hidden]
-bind = Super, mouse_down,global, quickshell:overviewToggleReleaseInterrupt # [hidden]
+binditn = Super, catchall, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Ctrl, Super_L, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Ctrl, Super_R, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:272, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:273, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:274, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:275, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:276, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse:277, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse_up, global, quickshell:searchToggleReleaseInterrupt # [hidden]
+bind = Super, mouse_down,global, quickshell:searchToggleReleaseInterrupt # [hidden]
bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden]
bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden]
+bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # Toggle overview
bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard
bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard
-bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # [hidden] Toggle overview/launcher (alt)
bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar
bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden]
bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden]
@@ -218,8 +218,8 @@ submap = global
#!
# Testing
-bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder:
" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden]
-bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Useless button" -A "action3=Cry more"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden]
+bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder:
" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden]
+bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden]
bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' # [hidden]
##! Session
diff --git a/dots/.config/quickshell/ii/GlobalStates.qml b/dots/.config/quickshell/ii/GlobalStates.qml
index 972495c64..85a0414d6 100644
--- a/dots/.config/quickshell/ii/GlobalStates.qml
+++ b/dots/.config/quickshell/ii/GlobalStates.qml
@@ -20,6 +20,7 @@ Singleton {
property bool overlayOpen: false
property bool overviewOpen: false
property bool regionSelectorOpen: false
+ property bool searchOpen: false
property bool screenLocked: false
property bool screenLockContainsCharacters: false
property bool screenUnlockFailed: false
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg
new file mode 100644
index 000000000..2cfa6dba7
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/power.svg b/dots/.config/quickshell/ii/assets/icons/fluent/power.svg
new file mode 100644
index 000000000..5c28fe986
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/power.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg
index af58d933f..84f42c500 100644
--- a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg
@@ -26,8 +26,8 @@
inkscape:zoom="4.65625"
inkscape:cx="32"
inkscape:cy="32"
- inkscape:window-width="1197"
- inkscape:window-height="1020"
+ inkscape:window-width="1595"
+ inkscape:window-height="664"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
@@ -48,10 +48,10 @@
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg
index 8d0e69fce..76af86e67 100644
--- a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg
@@ -23,10 +23,10 @@
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.5849319"
- inkscape:cx="26.95548"
+ inkscape:cx="27.031411"
inkscape:cy="26.423963"
- inkscape:window-width="1257"
- inkscape:window-height="1020"
+ inkscape:window-width="1621"
+ inkscape:window-height="820"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
@@ -35,10 +35,10 @@
id="defs2">
diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml
index 56f647684..9afbed44b 100644
--- a/dots/.config/quickshell/ii/modules/common/Directories.qml
+++ b/dots/.config/quickshell/ii/modules/common/Directories.qml
@@ -1,6 +1,7 @@
pragma Singleton
pragma ComponentBehavior: Bound
+import qs.services
import qs.modules.common.functions
import QtCore
import QtQuick
@@ -46,6 +47,9 @@ Singleton {
property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`)
property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`)
property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`)
+ property string userAvatarPathAccountsService: FileUtils.trimFileProtocol(`/var/lib/AccountsService/icons/${SystemInfo.username}`)
+ property string userAvatarPathRicersAndWeirdSystems: FileUtils.trimFileProtocol(`${Directories.home}.face`)
+ property string userAvatarPathRicersAndWeirdSystems2: FileUtils.trimFileProtocol(`${Directories.home}.face.icon`)
// Cleanup on init
Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml
index c360b536c..17dfc56c4 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml
@@ -12,4 +12,14 @@ Image {
Behavior on opacity {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
+
+ property list fallbacks: []
+ property int currentFallbackIndex: 0
+
+ onStatusChanged: {
+ if (status === Image.Error && currentFallbackIndex < fallbacks.length) {
+ source = fallbacks[currentFallbackIndex];
+ currentFallbackIndex += 1;
+ }
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml
index 53797fb66..4688b29be 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml
@@ -20,6 +20,7 @@ ToolTip {
hintingPreference: Font.PreferNoHinting // Prevent shaky text
}
+ delay: 0
visible: internalVisibleCondition
contentItem: StyledToolTipContent {
diff --git a/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml b/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml
index 248b46b56..c435f7f8a 100644
--- a/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml
+++ b/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml
@@ -162,7 +162,7 @@ Scope {
}
IpcHandler {
- target: "overview"
+ target: "search"
function toggle() {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
@@ -185,8 +185,8 @@ Scope {
}
GlobalShortcut {
- name: "overviewToggle"
- description: "Toggles overview on press"
+ name: "searchToggle"
+ description: "Toggles search on press"
onPressed: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
@@ -201,16 +201,8 @@ Scope {
}
}
GlobalShortcut {
- name: "overviewClose"
- description: "Closes overview"
-
- onPressed: {
- GlobalStates.overviewOpen = false;
- }
- }
- GlobalShortcut {
- name: "overviewToggleRelease"
- description: "Toggles overview on release"
+ name: "searchToggleRelease"
+ description: "Toggles search on release"
onPressed: {
GlobalStates.superReleaseMightTrigger = true;
@@ -225,8 +217,8 @@ Scope {
}
}
GlobalShortcut {
- name: "overviewToggleReleaseInterrupt"
- description: "Interrupts possibility of overview being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
+ name: "searchToggleReleaseInterrupt"
+ description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
onPressed: {
GlobalStates.superReleaseMightTrigger = false;
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
index 20af517fe..440695a2e 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml
@@ -66,7 +66,7 @@ BarButton {
}
}
- AppIcon {
+ WAppIcon {
id: iconWidget
anchors.centerIn: parent
iconName: root.iconName
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
index 5ec96eeb4..a92a85578 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml
@@ -14,8 +14,9 @@ AppButton {
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
iconName: down ? "start-here-pressed" : "start-here"
+ checked: GlobalStates.searchOpen
onClicked: {
- GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
+ GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
BarToolTip {
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml
index 51a3175bc..c1c16096b 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml
@@ -42,7 +42,7 @@ AppButton {
}
spacing: 6
- AppIcon {
+ WAppIcon {
id: iconWidget
anchors.verticalCenter: parent.verticalCenter
iconName: root.iconName
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml
index 2839a6747..9f114609f 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml
@@ -43,7 +43,7 @@ Button {
Layout.fillHeight: false
spacing: 8
- AppIcon {
+ WAppIcon {
id: appIcon
Layout.leftMargin: Looks.radius.large - root.padding + 2
Layout.alignment: Qt.AlignVCenter
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
index a321fa98e..609c9877b 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
@@ -54,6 +54,7 @@ Singleton {
property color controlFg: "#FFFFFF"
property color accentUnfocused: "#848484"
property color link: "#235CCF"
+ property color inputBg: ColorUtils.transparentize(bg0, 0.4)
}
darkColors: QtObject {
id: darkColors
@@ -71,7 +72,7 @@ Singleton {
property color bg2: '#8a8a8a'
property color bg2Hover: '#b1b1b1'
property color bg2Active: '#919191'
- property color bg2Border: '#c4c4c4'
+ property color bg2Border: '#bdbdbd'
property color subfg: "#CED1D7"
property color fg: "#FFFFFF"
property color fg1: "#D1D1D1"
@@ -82,6 +83,7 @@ Singleton {
property color controlFg: "#454545"
property color accentUnfocused: "#989898"
property color link: "#A7C9FC"
+ property color inputBg: ColorUtils.transparentize(darkColors.bg0, 0.5)
}
colors: QtObject {
id: colors
@@ -112,6 +114,7 @@ Singleton {
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
+ property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg
property color link: root.dark ? root.darkColors.link : root.lightColors.link
property color danger: "#C42B1C"
property color dangerActive: "#B62D1F"
@@ -121,6 +124,7 @@ Singleton {
property color accentActive: Appearance.colors.colPrimaryActive
property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused
property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000"
+ property color selection: Appearance.colors.colPrimaryContainer
}
radius: QtObject {
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml
similarity index 94%
rename from dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml
rename to dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml
index 48ff26104..6f71c65bb 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml
@@ -2,7 +2,6 @@ import QtQuick
import org.kde.kirigami as Kirigami
import qs.services
import qs.modules.common
-import qs.modules.waffle.looks
Kirigami.Icon {
id: root
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
index 6b2bc4ecb..ceed470ba 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml
@@ -53,10 +53,11 @@ Button {
// Hover stuff
signal hoverTimedOut
property bool shouldShowTooltip: false
+ ToolTip.delay: 400
property Timer hoverTimer: Timer {
id: hoverTimer
running: root.hovered
- interval: 400
+ interval: root.ToolTip.delay
onTriggered: {
root.hoverTimedOut();
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml
new file mode 100644
index 000000000..a3f3e8a40
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml
@@ -0,0 +1,18 @@
+import QtQuick
+import QtQuick.Controls
+
+TextInput {
+ id: root
+ renderType: Text.NativeRendering
+ verticalAlignment: Text.AlignVCenter
+ color: Looks.colors.fg
+
+ font {
+ hintingPreference: Font.PreferFullHinting
+ family: Looks.font.family.ui
+ pixelSize: Looks.font.pixelSize.large
+ weight: Looks.font.weight.regular
+ }
+
+ selectionColor: Looks.colors.selection
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
index 47ad2f92d..f49477988 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml
@@ -68,9 +68,8 @@ WBarAttachedPanelContent {
WPane {
id: calendarPane
- contentItem: ColumnLayout {
+ contentItem: WPanelPageColumn {
id: calendarColumnLayout
- spacing: 0
DateHeader {
Layout.fillWidth: true
Synchronizer on collapsed {
diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
index 856ddb160..895ab6892 100644
--- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml
@@ -13,7 +13,7 @@ MouseArea {
id: root
required property var notification
- property bool expanded: false
+ property bool expanded: notification.actions.length > 0
property string groupExpandControlMessage: ""
signal groupExpandToggle
hoverEnabled: true
@@ -58,13 +58,19 @@ MouseArea {
Loader {
id: imageLoader
+ anchors {
+ top: parent.top
+ left: parent.left
+ }
active: root.notification.image != ""
sourceComponent: StyledImage {
- width: 48
- height: 48
- sourceSize.width: width
- sourceSize.height: height
+ readonly property int size: 48
+ width: size
+ height: size
+ sourceSize.width: size
+ sourceSize.height: size
source: root.notification.image
+ fillMode: Image.PreserveAspectFit
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml
new file mode 100644
index 000000000..6bd23ae9b
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml
@@ -0,0 +1,84 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+FooterRectangle {
+ id: root
+
+ property bool searching: text.length > 0
+ property alias text: searchInput.text
+
+ Component.onCompleted: searchInput.forceActiveFocus()
+
+ focus: true
+ color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter
+
+ implicitWidth: 832 // TODO: Make sizes naturally inferred
+ implicitHeight: 63
+
+ Rectangle {
+ id: outline
+ anchors {
+ fill: parent
+ leftMargin: 32
+ rightMargin: 32
+ topMargin: 16
+ bottomMargin: 15
+ }
+ color: "transparent"
+ radius: height / 2
+ border.width: 1
+ border.color: Looks.colors.bg2Border
+ }
+
+ Rectangle {
+ id: searchInputBg
+ anchors.fill: outline
+ anchors.margins: 1
+ radius: height / 2
+ color: Looks.colors.inputBg
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 11
+
+ WAppIcon {
+ Layout.leftMargin: 14
+ iconName: "system-search-checked"
+ separateLightDark: true
+ implicitSize: 18
+ }
+
+ WTextInput {
+ id: searchInput
+ focus: true
+ Layout.fillWidth: true
+
+ WText {
+ anchors {
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ }
+ color: Looks.colors.accentUnfocused
+ text: Translation.tr("Search for apps") // should also have "", settings, and documents" but we don't have those
+ visible: searchInput.text.length === 0
+ font.pixelSize: Looks.font.pixelSize.large
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.IBeamCursor
+ acceptedButtons: Qt.NoButton
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml
new file mode 100644
index 000000000..cdbb7d3b8
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml
@@ -0,0 +1,16 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+BodyRectangle {
+ id: root
+
+
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml
new file mode 100644
index 000000000..6e97f88be
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml
@@ -0,0 +1,39 @@
+pragma ComponentBehavior: Bound
+import Qt.labs.synchronizer
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Quickshell
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.waffle.looks
+
+WBarAttachedPanelContent {
+ id: root
+
+ property bool searching: false
+ property string searchText: ""
+
+ contentItem: WPane {
+ contentItem: WPanelPageColumn {
+ SearchBar {
+ focus: true
+ Layout.fillWidth: true
+ Synchronizer on searching {
+ property alias target: root.searching
+ }
+ Synchronizer on text {
+ property alias source: root.searchText
+ }
+ }
+ Loader {
+ id: pageContentLoader
+ Layout.fillWidth: true
+ source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml"
+ }
+ }
+ }
+
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml
new file mode 100644
index 000000000..36e605187
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml
@@ -0,0 +1,98 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Qt5Compat.GraphicalEffects
+import Quickshell
+import org.kde.kirigami as Kirigami
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.functions
+import qs.modules.common.widgets
+import qs.modules.waffle.looks
+
+WPanelPageColumn {
+ id: root
+
+ WPanelSeparator {}
+
+ BodyRectangle {
+ implicitHeight: 736 // TODO: Make sizes naturally inferred
+ }
+
+ WPanelSeparator {}
+
+ StartFooter {
+ Layout.fillWidth: true
+ }
+
+ component StartFooter: FooterRectangle {
+ implicitHeight: 63
+
+ UserButton {
+ anchors {
+ left: parent.left
+ leftMargin: 52
+ bottom: parent.bottom
+ bottomMargin: 12
+ }
+ }
+
+ PowerButton {
+ anchors {
+ right: parent.right
+ rightMargin: 52
+ bottom: parent.bottom
+ bottomMargin: 12
+ }
+ }
+ }
+
+ component UserButton: WBorderlessButton {
+ id: userButton
+ implicitWidth: userButtonRow.implicitWidth + 12 * 2
+ implicitHeight: 40
+
+ contentItem: Item {
+ RowLayout {
+ id: userButtonRow
+ anchors.centerIn: parent
+ spacing: 12
+
+ StyledImage {
+ id: avatar
+ // Use this for free fallback because I'm lazy
+ Layout.alignment: Qt.AlignTop
+ sourceSize: Qt.size(32, 32)
+ source: Directories.userAvatarPathAccountsService
+ fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
+
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Circle {
+ diameter: avatar.height
+ }
+ }
+ }
+ WText {
+ Layout.alignment: Qt.AlignVCenter
+ text: SystemInfo.username
+ }
+ }
+ }
+ }
+
+ component PowerButton: WBorderlessButton {
+ implicitWidth: 40
+ implicitHeight: 40
+
+ contentItem: Item {
+ FluentIcon {
+ anchors.centerIn: parent
+ icon: "power"
+ implicitSize: 20
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml
new file mode 100644
index 000000000..9b59fb0c8
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml
@@ -0,0 +1,119 @@
+import QtQuick
+import Quickshell
+import Quickshell.Io
+import Quickshell.Wayland
+import Quickshell.Hyprland
+import qs
+import qs.services
+import qs.modules.common
+import qs.modules.common.widgets
+
+Scope {
+ id: root
+
+ Connections {
+ target: GlobalStates
+
+ function onSearchOpenChanged() {
+ if (GlobalStates.searchOpen)
+ panelLoader.active = true;
+ }
+ }
+
+ Loader {
+ id: panelLoader
+ active: GlobalStates.searchOpen
+ sourceComponent: PanelWindow {
+ id: panelWindow
+ exclusiveZone: 0
+ WlrLayershell.namespace: "quickshell:wStartMenu"
+ WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
+ color: "transparent"
+
+ anchors {
+ bottom: Config.options.waffles.bar.bottom
+ top: !Config.options.waffles.bar.bottom
+ left: Config.options.waffles.bar.leftAlignApps
+ }
+
+ implicitWidth: content.implicitWidth
+ implicitHeight: content.implicitHeight
+
+ HyprlandFocusGrab {
+ id: focusGrab
+ active: true
+ windows: [panelWindow]
+ onCleared: content.close()
+ }
+
+ Connections {
+ target: GlobalStates
+ function onSearchOpenChanged() {
+ if (!GlobalStates.searchOpen)
+ content.close();
+ }
+ }
+
+ StartMenuContent {
+ id: content
+ anchors.fill: parent
+ focus: true
+
+ onClosed: {
+ GlobalStates.searchOpen = false;
+ panelLoader.active = false;
+ }
+ }
+ }
+ }
+
+ IpcHandler {
+ target: "search"
+
+ function toggle() {
+ GlobalStates.searchOpen = !GlobalStates.searchOpen;
+ }
+ function close() {
+ GlobalStates.searchOpen = false;
+ }
+ function open() {
+ GlobalStates.searchOpen = true;
+ }
+ function toggleReleaseInterrupt() {
+ GlobalStates.superReleaseMightTrigger = false;
+ }
+ }
+
+ GlobalShortcut {
+ name: "searchToggle"
+ description: "Toggles search on press"
+
+ onPressed: {
+ GlobalStates.searchOpen = !GlobalStates.searchOpen;
+ }
+ }
+ GlobalShortcut {
+ name: "searchToggleRelease"
+ description: "Toggles search on release"
+
+ onPressed: {
+ GlobalStates.superReleaseMightTrigger = true;
+ }
+
+ onReleased: {
+ if (!GlobalStates.superReleaseMightTrigger) {
+ GlobalStates.superReleaseMightTrigger = true;
+ return;
+ }
+ GlobalStates.searchOpen = !GlobalStates.searchOpen;
+ }
+ }
+ GlobalShortcut {
+ name: "searchToggleReleaseInterrupt"
+ description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
+
+ onPressed: {
+ GlobalStates.superReleaseMightTrigger = false;
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml
index 3f57c0c28..7bb565d11 100644
--- a/dots/.config/quickshell/ii/shell.qml
+++ b/dots/.config/quickshell/ii/shell.qml
@@ -33,6 +33,7 @@ import qs.modules.waffle.background
import qs.modules.waffle.bar
import qs.modules.waffle.notificationCenter
import qs.modules.waffle.onScreenDisplay
+import qs.modules.waffle.startMenu
import QtQuick
import QtQuick.Window
@@ -77,11 +78,13 @@ ShellRoot {
PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} }
PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} }
PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} }
+
PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} }
PanelLoader { identifier: "wBar"; component: WaffleBar {} }
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
+ PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} }
ReloadPopup {}
component PanelLoader: LazyLoader {
@@ -94,7 +97,7 @@ ShellRoot {
property list families: ["ii", "waffle"]
property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
- "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
+ "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
})
function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily)
From b45f2dd235f1e4e868d5748688ea4e23088c4f30 Mon Sep 17 00:00:00 2001
From: jwihardi
Date: Sun, 30 Nov 2025 15:31:02 -0500
Subject: [PATCH 037/154] added libqalculate gentoo
---
...ets-1.0-r3.ebuild => illogical-impulse-widgets-1.0-r4.ebuild} | 1 +
1 file changed, 1 insertion(+)
rename sdata/dist-gentoo/illogical-impulse-widgets/{illogical-impulse-widgets-1.0-r3.ebuild => illogical-impulse-widgets-1.0-r4.ebuild} (95%)
diff --git a/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild b/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild
similarity index 95%
rename from sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild
rename to sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild
index 95ffeffba..9ffceea09 100644
--- a/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild
+++ b/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild
@@ -21,6 +21,7 @@ RDEPEND="
app-misc/songrec
app-i18n/translate-shell
gui-apps/wlogout
+ sci-libs/libqalculate
"
##### CUSTOM EBUILDS
# app-misc/songrec
From 8d2c8bd38ee48e96c7751ffaf3595e5056a460e3 Mon Sep 17 00:00:00 2001
From: end-4 <97237370+end-4@users.noreply.github.com>
Date: Mon, 1 Dec 2025 13:27:01 +0100
Subject: [PATCH 038/154] waffles: power menu and user account menu
---
.../ii/assets/icons/fluent/corporation.svg | 17 ++
.../icons/fluent/start-here-pressed.svg | 142 +++++++++++++---
.../ii/assets/icons/fluent/start-here.svg | 142 +++++++++++++---
.../quickshell/ii/modules/common/Config.qml | 1 +
.../ii/modules/waffle/looks/WIcons.qml | 4 +
.../ii/modules/waffle/looks/WMenu.qml | 83 +++++++++
.../ii/modules/waffle/looks/WMenuItem.qml | 93 +++++++++++
.../ii/modules/waffle/looks/WPane.qml | 2 +-
.../ii/modules/waffle/looks/WToolTip.qml | 2 +
.../modules/waffle/looks/WToolTipContent.qml | 1 +
.../ii/modules/waffle/looks/WUserAvatar.qml | 27 +++
.../notificationCenter/WNotificationGroup.qml | 1 +
.../waffle/startMenu/StartPageContent.qml | 157 ++++++++++++++++--
13 files changed, 611 insertions(+), 61 deletions(-)
create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WMenuItem.qml
create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WUserAvatar.qml
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg b/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg
new file mode 100644
index 000000000..0ed1a0319
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg
@@ -0,0 +1,17 @@
+
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg b/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg
index e6b950eca..2efc81c45 100644
--- a/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg
@@ -1,24 +1,120 @@
-