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] 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)