Personal noctalia plugins collection

fix: use wide date range and local filtering for event display

CalendarService.loadEvents() replaces all cached events with only the
requested date window. The previous approach called loadEvents() on
every week navigation, causing a race with CalendarService's internal
5-minute auto-refresh (which uses narrow defaults of 31/14 days).

Key changes:
- Request wide range (180 days back, 60 days ahead) on initial load
- Navigate weeks via refreshView() which re-filters locally
- Detect when auto-refresh narrows events and re-request wide range
- Process cached events immediately on startup (before EDS is ready)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+46 -20
+42 -15
weekly-calendar/Main.qml
··· 16 16 property bool isLoading: false 17 17 property bool hasLoadedOnce: false 18 18 property string syncStatus: "" 19 + property int lastKnownEventCount: 0 19 20 20 21 property real dayColumnWidth: 120 * Style.uiScaleRatio 21 22 property real allDaySectionHeight: 0 * Style.uiScaleRatio ··· 44 45 45 46 readonly property color lineColor: lineColorTypeSetting === "mOnSurfaceVariant" ? Color.mOnSurfaceVariant : Color.mOutline 46 47 47 - onWeekStartSettingChanged: if (hasLoadedOnce) Qt.callLater(loadEvents) 48 + onWeekStartSettingChanged: if (hasLoadedOnce) Qt.callLater(refreshView) 48 49 onTimeFormatSettingChanged: eventsModelChanged() 49 - onCurrentDateChanged: Qt.callLater(loadEvents) 50 + onCurrentDateChanged: Qt.callLater(refreshView) 50 51 onLineColorTypeSettingChanged: eventsModelChanged() 51 52 onHourLineOpacitySettingChanged: eventsModelChanged() 52 53 onDayLineOpacitySettingChanged: eventsModelChanged() ··· 63 64 } 64 65 } 65 66 function onEventsChanged() { 66 - if (isLoading || hasLoadedOnce) { 67 - Qt.callLater(updateEventsFromService) 67 + var count = CalendarService.events ? CalendarService.events.length : 0 68 + // If auto-refresh dropped event count significantly, re-request wide range 69 + if (hasLoadedOnce && !isLoading && lastKnownEventCount > 10 && count < lastKnownEventCount * 0.5) { 70 + console.log("[weekly-calendar] Auto-refresh narrowed events (" + count + " vs " + lastKnownEventCount + "), re-requesting wide range") 71 + Qt.callLater(loadEvents) 72 + return 68 73 } 74 + lastKnownEventCount = Math.max(lastKnownEventCount, count) 75 + Qt.callLater(updateEventsFromService) 69 76 } 70 77 function onLoadingChanged() { 71 78 if (!CalendarService.loading && isLoading) { ··· 95 102 96 103 Component.onCompleted: { 97 104 initializePluginSettings() 105 + // Process any cached events immediately 106 + if (CalendarService.events && CalendarService.events.length > 0) { 107 + Qt.callLater(updateEventsFromService) 108 + } 98 109 if (CalendarService.available) Qt.callLater(loadEvents) 99 110 } 100 111 101 112 onPluginApiChanged: { 102 113 initializePluginSettings() 114 + if (CalendarService.events && CalendarService.events.length > 0) { 115 + Qt.callLater(updateEventsFromService) 116 + } 103 117 if (CalendarService.available) Qt.callLater(loadEvents) 104 118 } 105 119 ··· 119 133 120 134 function initializePlugin() { 121 135 console.log("[weekly-calendar] initializePlugin called, CalendarService.available=" + CalendarService.available) 122 - loadEvents() 136 + if (!hasLoadedOnce && CalendarService.available) { 137 + loadEvents() 138 + } else { 139 + refreshView() 140 + } 141 + } 142 + 143 + // Re-filter existing events for the current week view (no new fetch) 144 + function refreshView() { 145 + if (!pluginApi) return 146 + if (CalendarService.events && CalendarService.events.length > 0) { 147 + updateEventsFromService() 148 + } else if (hasLoadedOnce) { 149 + clearEventModels() 150 + syncStatus = pluginApi.tr("panel.no_events") 151 + } 123 152 } 124 153 125 - // Fetch events - kicks off async request, signals will deliver results 154 + // Fetch events from EDS - requests a wide date range to cover past/future navigation 126 155 function loadEvents() { 127 156 if (!pluginApi) return 128 157 if (!CalendarService.available) { 129 158 syncStatus = pluginApi.tr("panel.no_service") 159 + console.log("[weekly-calendar] loadEvents: service not available") 130 160 return 131 161 } 132 162 133 163 isLoading = true 134 164 syncStatus = pluginApi.tr("panel.loading") 135 165 136 - var now = new Date() 137 - var start = new Date(weekStart), end = new Date(weekEnd) 138 - start.setDate(start.getDate() - 7) 139 - end.setDate(end.getDate() + 14) 166 + // Request a wide range: 180 days behind, 60 days ahead 167 + // This covers ~6 months of past events and ~2 months of future events 168 + var daysAhead = 60 169 + var daysBehind = 180 140 170 141 - CalendarService.loadEvents( 142 - Math.max(0, Math.ceil((end - now) / 86400000)), 143 - Math.max(0, Math.ceil((now - start) / 86400000)) 144 - ) 171 + CalendarService.loadEvents(daysAhead, daysBehind) 145 172 146 173 hasLoadedOnce = true 147 174 loadingTimeout.restart() 148 175 149 - // If CalendarService already has events (cached), process them now 176 + // If CalendarService already has events (cached), display them now 150 177 if (CalendarService.events && CalendarService.events.length > 0) { 151 178 Qt.callLater(updateEventsFromService) 152 179 }
+4 -5
weekly-calendar/Panel.qml
··· 30 30 // When panel opens, trigger a fresh load if needed. 31 31 Component.onCompleted: mainInstance?.initializePlugin() 32 32 onVisibleChanged: if (visible && mainInstance) { 33 - mainInstance.loadEvents() 33 + mainInstance.refreshView() 34 34 mainInstance.goToToday() 35 35 Qt.callLater(root.scrollToCurrentTime) 36 36 } ··· 274 274 } 275 275 NIconButton { 276 276 icon: "chevron-left" 277 - onClicked: { mainInstance?.navigateWeek(-7); mainInstance?.loadEvents() } 277 + onClicked: mainInstance?.navigateWeek(-7) 278 278 } 279 279 NIconButton { 280 280 icon: "calendar"; tooltipText: pluginApi.tr("panel.today") 281 - onClicked: { mainInstance?.goToToday(); mainInstance?.loadEvents(); Qt.callLater(root.scrollToCurrentTime) } 281 + onClicked: { mainInstance?.goToToday(); Qt.callLater(root.scrollToCurrentTime) } 282 282 } 283 283 NIconButton { 284 284 icon: "chevron-right" 285 - onClicked: { mainInstance?.navigateWeek(7); mainInstance?.loadEvents() } 285 + onClicked: mainInstance?.navigateWeek(7) 286 286 } 287 287 NIconButton { 288 288 icon: "refresh"; tooltipText: I18n.tr("common.refresh") ··· 452 452 } else if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) { 453 453 if (mainInstance) { 454 454 mainInstance.navigateWeek(event.key === Qt.Key_Left ? -7 : 7) 455 - mainInstance.loadEvents() 456 455 } 457 456 event.accepted = true 458 457 }