@@ -36,6 +36,7 @@ def cache_notification_pixbuf(notification_box): # Pass notification_box instead
36
36
scaled = notification .image_pixbuf .scale_simple (48 , 48 , GdkPixbuf .InterpType .BILINEAR )
37
37
scaled .savev (cache_file , "png" , [], [])
38
38
notification_box .cached_image_path = cache_file # Store in notification_box
39
+ logger .info (f"Cached image to: { cache_file } " )
39
40
except Exception as e :
40
41
logger .error (f"Error caching the image: { e } " )
41
42
@@ -49,15 +50,17 @@ def load_scaled_pixbuf(notification_box, width, height): # Pass notification_box
49
50
return None # Handle the case where notification is not available
50
51
51
52
pixbuf = None
52
- # Check if this is a historical notification by checking if it has 'cached_image_path' and it exists
53
+ # Check if cached_image_path exists and use cached image if available
53
54
if hasattr (notification_box , "cached_image_path" ) and notification_box .cached_image_path and os .path .exists (notification_box .cached_image_path ):
54
55
try :
55
56
pixbuf = GdkPixbuf .Pixbuf .new_from_file (notification_box .cached_image_path )
56
57
pixbuf = pixbuf .scale_simple (width , height , GdkPixbuf .InterpType .BILINEAR )
58
+ logger .debug (f"Loaded cached image from: { notification_box .cached_image_path } " )
57
59
return pixbuf
58
60
except Exception as e :
59
61
logger .error (f"Error loading cached image from { notification_box .cached_image_path } : { e } " )
60
- # If not historical or no cached image, load from notification or app icon directly
62
+ # Fallback to loading from notification if cached load fails
63
+ # If no cached image or loading failed, load from notification or app icon directly
61
64
if notification .image_pixbuf : # Use notification.image_pixbuf
62
65
pixbuf = notification .image_pixbuf .scale_simple (width , height , GdkPixbuf .InterpType .BILINEAR )
63
66
return pixbuf
@@ -133,6 +136,10 @@ def __init__(self, notification: Notification, timeout_ms=5000, **kwargs):
133
136
self .connect ("leave-notify-event" , self .on_hover_leave )
134
137
135
138
self ._destroyed = False
139
+ self ._is_history = False # Flag to indicate if this box is in history
140
+
141
+ def set_is_history (self , is_history ):
142
+ self ._is_history = is_history
136
143
137
144
def set_container (self , container ):
138
145
self ._container = container
@@ -275,9 +282,9 @@ def close_notification(self):
275
282
pass
276
283
return False
277
284
278
- def destroy (self ):
279
- logger .debug (f"NotificationBox destroy called for notification: { self .notification .id } " )
280
- if hasattr (self , "cached_image_path" ) and self .cached_image_path and os .path .exists (self .cached_image_path ):
285
+ def destroy (self , from_history_delete = False ): # Add from_history_delete flag, although not used now
286
+ logger .debug (f"NotificationBox destroy called for notification: { self .notification .id } , from_history_delete: { from_history_delete } , is_history: { self . _is_history } " )
287
+ if hasattr (self , "cached_image_path" ) and self .cached_image_path and os .path .exists (self .cached_image_path ) and not self . _is_history : # Delete cache if not history notification
281
288
try :
282
289
os .remove (self .cached_image_path )
283
290
logger .info (f"Deleted cached image: { self .cached_image_path } " )
@@ -391,27 +398,20 @@ def clear_history(self, *args):
391
398
"""Clears the notification history (visual and persistent)."""
392
399
# Clear visual history
393
400
for child in self .notifications_list .get_children ()[:]: # Iterate over a copy to avoid issues with removing children
401
+ container = child # Child is the container box
402
+ notif_box = container .notification_box if hasattr (container , "notification_box" ) else None # Access notification_box from container
403
+ if notif_box :
404
+ notif_box .destroy (from_history_delete = True ) # Call destroy with flag for history delete
394
405
self .notifications_list .remove (child )
395
406
child .destroy ()
407
+
396
408
# Clear persistent history
397
409
if os .path .exists (PERSISTENT_HISTORY_FILE ):
398
410
try :
399
- with open (PERSISTENT_HISTORY_FILE , "r" ) as f :
400
- persistent_data = json .load (f )
401
- # Delete cached images from persistent history before clearing the list
402
- for note in persistent_data :
403
- cached_image_path = note .get ("id" ) # Use 'id' (UUID) to find cached image
404
- cached_image_file = os .path .join (PERSISTENT_DIR , f"notification_{ cached_image_path } .png" )
405
- if cached_image_file and os .path .exists (cached_image_file ):
406
- try :
407
- os .remove (cached_image_file )
408
- logger .info (f"Deleted cached image: { cached_image_file } " )
409
- except Exception as e :
410
- logger .error (f"Error deleting cached image { cached_image_file } : { e } " )
411
411
os .remove (PERSISTENT_HISTORY_FILE )
412
412
logger .info ("Notification history cleared and persistent file deleted." )
413
413
except Exception as e :
414
- logger .error (f"Error deleting persistent history file or cached images : { e } " )
414
+ logger .error (f"Error deleting persistent history file: { e } " )
415
415
self .persistent_notifications = [] # Clear in memory list after file operations
416
416
self .update_separators ()
417
417
self .update_no_notifications_label_visibility () # Update label visibility after clearing
@@ -443,15 +443,10 @@ def delete_historical_notification(self, note_id, container):
443
443
Deletes a historical notification (visual and persistent) and deletes its related files.
444
444
"""
445
445
# Delete the cached file, if it exists BEFORE updating persistent list
446
- if hasattr (container , "notification" ):
447
- notif = container .notification
448
- cached_image_path = container .notification .cached_image_path # Use cached_image_path from container.notification
449
- if cached_image_path and os .path .exists (cached_image_path ):
450
- try :
451
- os .remove (cached_image_path )
452
- logger .info (f"Deleted cached image: { cached_image_path } " )
453
- except Exception as e :
454
- logger .error (f"Error deleting the cached image: { e } " )
446
+ if hasattr (container , "notification_box" ):
447
+ notif_box = container .notification_box
448
+ notif_box .destroy (from_history_delete = True ) # Call destroy with flag to delete cache
449
+
455
450
# Update the persistent list
456
451
self .persistent_notifications = [
457
452
note for note in self .persistent_notifications if note .get ("id" ) != note_id
@@ -478,6 +473,7 @@ def _add_historical_notification(self, note):
478
473
hist_box = NotificationBox (hist_notif , timeout_ms = 0 ) # Use historical notification object
479
474
hist_box .uuid = hist_notif .id # Assign UUID to hist_box as well
480
475
hist_box .cached_image_path = hist_notif .cached_image_path # Restore cached image path
476
+ hist_box .set_is_history (True ) # Mark as history box
481
477
# Action buttons are removed as they are not necessary in history
482
478
for child in hist_box .get_children ():
483
479
if child .get_name () == "notification-action-buttons" :
@@ -488,6 +484,7 @@ def _add_historical_notification(self, note):
488
484
h_align = "fill" ,
489
485
h_expand = True ,
490
486
)
487
+ container .notification_box = hist_box # Store notification_box in container
491
488
# Convert the timestamp to a datetime object; if it fails, datetime.now() is used
492
489
try :
493
490
arrival = datetime .fromisoformat (hist_notif .timestamp )
@@ -592,29 +589,27 @@ def add_notification(self, notification_box):
592
589
oldest_notification_container = self .notifications_list .get_children ()[0 ]
593
590
self .notifications_list .remove (oldest_notification_container )
594
591
# Delete cached image of the oldest notification when removing from history limit
595
- if hasattr (oldest_notification_container , "notification " ) and hasattr (oldest_notification_container .notification , "cached_image_path" ) and oldest_notification_container .notification .cached_image_path and os .path .exists (oldest_notification_container .notification .cached_image_path ):
592
+ if hasattr (oldest_notification_container , "notification_box " ) and hasattr (oldest_notification_container .notification_box , "cached_image_path" ) and oldest_notification_container .notification_box .cached_image_path and os .path .exists (oldest_notification_container .notification_box .cached_image_path ):
596
593
try :
597
- os .remove (oldest_notification_container .notification .cached_image_path )
598
- logger .info (f"Deleted cached image of oldest notification due to history limit: { oldest_notification_container .notification .cached_image_path } " )
594
+ os .remove (oldest_notification_container .notification_box .cached_image_path )
595
+ logger .info (f"Deleted cached image of oldest notification due to history limit: { oldest_notification_container .notification_box .cached_image_path } " )
599
596
except Exception as e :
600
597
logger .error (f"Error deleting cached image of oldest notification: { e } " )
601
598
oldest_notification_container .destroy () # Destroy the container as well
602
599
603
- # Cache the image when adding to history
604
- if notification_box .notification .image_pixbuf :
605
- cache_notification_pixbuf (notification_box )
606
600
607
601
def on_container_destroy (container ):
608
602
if hasattr (container , "_timestamp_timer_id" ) and container ._timestamp_timer_id :
609
603
GLib .source_remove (container ._timestamp_timer_id )
610
604
if hasattr (container , "notification_box" ): # Use container.notification_box
611
605
notif_box = container .notification_box
612
- if hasattr (notif_box , "cached_image_path" ) and notif_box .cached_image_path and os .path .exists (notif_box .cached_image_path ):
613
- try :
614
- os .remove (notif_box .cached_image_path )
615
- logger .info (f"Deleted cached image on container destroy: { notif_box .cached_image_path } " )
616
- except Exception as e :
617
- logger .error (f"Error deleting the cached image on container destroy: { e } " )
606
+ # Do NOT delete cached image here, it's needed for history. Deletion is handled when clearing history or deleting historical notification explicitly.
607
+ # if hasattr(notif_box, "cached_image_path") and notif_box.cached_image_path and os.path.exists(notif_box.cached_image_path):
608
+ # try:
609
+ # os.remove(notif_box.cached_image_path)
610
+ # logger.info(f"Deleted cached image on container destroy: {notif_box.cached_image_path}")
611
+ # except Exception as e:
612
+ # logger.error(f"Error deleting the cached image on container destroy: {e}")
618
613
container .destroy ()
619
614
GLib .idle_add (self .update_separators )
620
615
self .update_no_notifications_label_visibility () # Update label visibility after removing
@@ -839,16 +834,15 @@ def on_new_notification(self, fabric_notif, id):
839
834
notification = fabric_notif .get_notification_from_id (id )
840
835
new_box = NotificationBox (notification )
841
836
if notification .image_pixbuf :
842
- cache_notification_pixbuf ( new_box ) # Cache synchronously before adding to history, pass notification_box
837
+ GLib . idle_add ( cache_notification_pixbuf , new_box ) # Cache synchronously before adding to history, pass notification_box
843
838
# Do NOT set container or connect closed signal as it's for history only
844
839
self .notch .notification_history .add_notification (new_box ) # Directly add to history
845
840
return # Exit early, do not proceed with displaying live notification
846
841
847
842
notification = fabric_notif .get_notification_from_id (id )
848
843
new_box = NotificationBox (notification )
849
- # Do not cache image here, only cache when adding to history
850
- # if notification.image_pixbuf:
851
- # GLib.idle_add(cache_notification_pixbuf, new_box) # Pass notification_box to cache
844
+ if notification .image_pixbuf :
845
+ GLib .idle_add (cache_notification_pixbuf , new_box ) # Cache image on arrival asynchronously
852
846
new_box .set_container (self )
853
847
notification .connect ("closed" , self .on_notification_closed )
854
848
while len (self .notifications ) >= 5 :
@@ -888,17 +882,19 @@ def on_notification_closed(self, notification, reason):
888
882
return
889
883
i , notif_box = notif_to_remove
890
884
reason_str = str (reason )
891
- if (reason_str == "NotificationCloseReason.EXPIRED" or
892
- reason_str == "NotificationCloseReason.CLOSED" or
893
- reason_str == "NotificationCloseReason.UNDEFINED" or
894
- reason_str == "NotificationCloseReason.DISMISSED_BY_USER" ): # Also cleanup when dismissed by user
895
- logger .info (f"Cleaning up cached image for notification { notification .id } " )
896
- notif_box .destroy () # Call destroy to cleanup resources, including cached image
897
-
898
- if reason_str == "NotificationCloseReason.EXPIRED" or reason_str == "NotificationCloseReason.CLOSED" or reason_str == "NotificationCloseReason.UNDEFINED" :
899
- logger .info (f"Adding notification { notification .id } to history" )
885
+ if reason_str == "NotificationCloseReason.DISMISSED_BY_USER" :
886
+ logger .info (f"Cleaning up resources for dismissed notification { notification .id } " )
887
+ notif_box .destroy () # Destroy and delete cache for user dismissed notifications
888
+ elif (reason_str == "NotificationCloseReason.EXPIRED" or
889
+ reason_str == "NotificationCloseReason.CLOSED" or
890
+ reason_str == "NotificationCloseReason.UNDEFINED" ):
891
+ logger .info (f"Adding notification { notification .id } to history (reason: { reason_str } )" )
892
+ notif_box .set_is_history (True ) # Set is_history to True before adding to history
900
893
self .notch .notification_history .add_notification (notif_box )
901
-
894
+ notif_box .stop_timeout () # Ensure timeout is stopped, but do not destroy yet, history add takes care of it indirectly via container destroy
895
+ else :
896
+ logger .warning (f"Unknown close reason: { reason_str } for notification { notification .id } . Defaulting to destroy." )
897
+ notif_box .destroy () # Fallback destroy for unknown reasons
902
898
903
899
if len (self .notifications ) == 1 :
904
900
self ._is_destroying = True
@@ -929,6 +925,7 @@ def _destroy_container(self):
929
925
self .notifications .clear ()
930
926
self ._destroyed_notifications .clear ()
931
927
for child in self .stack .get_children ():
928
+ child .destroy () # Destroy each child (NotificationBox) properly
932
929
self .stack .remove (child )
933
930
self .current_index = 0
934
931
self .navigation .set_visible (False )
0 commit comments