Personal noctalia plugins collection
1import QtQuick
2import Quickshell
3import qs.Commons
4import qs.Widgets
5import qs.Modules.Bar.Extras
6import qs.Services.UI
7
8Item {
9 id: root
10
11 property QtObject pluginApi: null
12 readonly property QtObject pluginCore: pluginApi?.mainInstance
13
14 property ShellScreen screen
15 property string widgetId: ""
16 property string section: ""
17 property int sectionWidgetIndex: -1
18 property int sectionWidgetsCount: 0
19
20 property string tooltipContent: ""
21
22 Timer {
23 id: updateTimer
24 interval: 1000
25 running: true
26 repeat: true
27 onTriggered: updateTooltip()
28 }
29
30 function updateTooltip() {
31 if (!pluginCore || !pluginCore.eventsModel) {
32 tooltipContent = "";
33 return;
34 }
35
36 var events = pluginCore.eventsModel;
37 var now = new Date();
38
39 // Get start and end of today
40 var todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
41 var todayEnd = new Date(todayStart);
42 todayEnd.setDate(todayEnd.getDate() + 1);
43
44 var currentEv = null;
45 var nextEv = null;
46 var hasEventsToday = false;
47
48 for (var i = 0; i < events.count; i++) {
49 var event = events.get(i);
50 var eventStart = event.startTime;
51 var eventEnd = event.endTime;
52
53 // Only consider events that occur today
54 var occursToday = (eventStart >= todayStart && eventStart < todayEnd) ||
55 (eventEnd > todayStart && eventEnd <= todayEnd) ||
56 (eventStart < todayStart && eventEnd > todayEnd);
57
58 if (!occursToday) {
59 continue;
60 }
61
62 hasEventsToday = true;
63
64 // Check if event is currently happening
65 if (now >= eventStart && now <= eventEnd) {
66 currentEv = event;
67 }
68
69 // Check for next event (starting later today)
70 if (!nextEv && eventStart > now && eventStart < todayEnd) {
71 nextEv = event;
72 }
73
74 if (currentEv && nextEv) break;
75 }
76
77 var tip = "";
78
79 if (currentEv) {
80 tip = pluginApi.tr("bar_widget.now") + ": " + currentEv.title + "\n" +
81 pluginCore.formatTimeRangeForDisplay(currentEv);
82
83 // If there's a current event and a next event
84 if (nextEv) {
85 tip += "\n\n" + pluginApi.tr("bar_widget.next") + ": " + nextEv.title + "\n" +
86 pluginCore.formatTimeRangeForDisplay(nextEv);
87 }
88 }
89
90 if (nextEv && !currentEv) {
91 // If no current event but there's a next event today
92 tip = pluginApi.tr("bar_widget.next") + ": " + nextEv.title + "\n" +
93 pluginCore.formatTimeRangeForDisplay(nextEv);
94 }
95
96 // If all events have passed today
97 if (!tip && hasEventsToday) {
98 tip = pluginApi.tr("bar_widget.no_more_events_today");
99 }
100
101 tooltipContent = tip;
102 }
103
104 Connections {
105 target: pluginCore
106 function onEventsModelChanged() { updateTooltip(); }
107 function onCurrentDateChanged() { updateTooltip(); }
108 }
109
110 implicitWidth: pill.width
111 implicitHeight: pill.height
112
113 BarPill {
114 id: pill
115 screen: root.screen
116 oppositeDirection: BarService.getPillDirection(root)
117 forceClose: true
118
119 icon: "calendar"
120 tooltipText: tooltipContent
121
122 onClicked: root.pluginApi?.openPanel(root.screen)
123
124 onRightClicked: {
125 PanelService.showContextMenu(contextMenu, pill, root.screen);
126 }
127 }
128
129 NPopupContextMenu {
130 id: contextMenu
131 model: [
132 {
133 "label": pluginApi.tr("bar_widget.settings"),
134 "action": "widget-settings",
135 "icon": "settings",
136 "enabled": true
137 }
138 ]
139
140 onTriggered: action => {
141 contextMenu.close();
142 PanelService.closeContextMenu(root.screen);
143
144 if (action === "widget-settings") {
145 BarService.openPluginSettings(screen, pluginApi.manifest);
146 }
147 }
148 }
149}