Skip to content

Commit 5dec800

Browse files
committed
NOTIFICATIONS ARE HARD (But now they work)
1 parent 87ce069 commit 5dec800

File tree

1 file changed

+50
-53
lines changed

1 file changed

+50
-53
lines changed

modules/notifications.py

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def cache_notification_pixbuf(notification_box): # Pass notification_box instead
3636
scaled = notification.image_pixbuf.scale_simple(48, 48, GdkPixbuf.InterpType.BILINEAR)
3737
scaled.savev(cache_file, "png", [], [])
3838
notification_box.cached_image_path = cache_file # Store in notification_box
39+
logger.info(f"Cached image to: {cache_file}")
3940
except Exception as e:
4041
logger.error(f"Error caching the image: {e}")
4142

@@ -49,15 +50,17 @@ def load_scaled_pixbuf(notification_box, width, height): # Pass notification_box
4950
return None # Handle the case where notification is not available
5051

5152
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
5354
if hasattr(notification_box, "cached_image_path") and notification_box.cached_image_path and os.path.exists(notification_box.cached_image_path):
5455
try:
5556
pixbuf = GdkPixbuf.Pixbuf.new_from_file(notification_box.cached_image_path)
5657
pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
58+
logger.debug(f"Loaded cached image from: {notification_box.cached_image_path}")
5759
return pixbuf
5860
except Exception as e:
5961
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
6164
if notification.image_pixbuf: # Use notification.image_pixbuf
6265
pixbuf = notification.image_pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
6366
return pixbuf
@@ -133,6 +136,10 @@ def __init__(self, notification: Notification, timeout_ms=5000, **kwargs):
133136
self.connect("leave-notify-event", self.on_hover_leave)
134137

135138
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
136143

137144
def set_container(self, container):
138145
self._container = container
@@ -275,9 +282,9 @@ def close_notification(self):
275282
pass
276283
return False
277284

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
281288
try:
282289
os.remove(self.cached_image_path)
283290
logger.info(f"Deleted cached image: {self.cached_image_path}")
@@ -391,27 +398,20 @@ def clear_history(self, *args):
391398
"""Clears the notification history (visual and persistent)."""
392399
# Clear visual history
393400
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
394405
self.notifications_list.remove(child)
395406
child.destroy()
407+
396408
# Clear persistent history
397409
if os.path.exists(PERSISTENT_HISTORY_FILE):
398410
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}")
411411
os.remove(PERSISTENT_HISTORY_FILE)
412412
logger.info("Notification history cleared and persistent file deleted.")
413413
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}")
415415
self.persistent_notifications = [] # Clear in memory list after file operations
416416
self.update_separators()
417417
self.update_no_notifications_label_visibility() # Update label visibility after clearing
@@ -443,15 +443,10 @@ def delete_historical_notification(self, note_id, container):
443443
Deletes a historical notification (visual and persistent) and deletes its related files.
444444
"""
445445
# 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+
455450
# Update the persistent list
456451
self.persistent_notifications = [
457452
note for note in self.persistent_notifications if note.get("id") != note_id
@@ -478,6 +473,7 @@ def _add_historical_notification(self, note):
478473
hist_box = NotificationBox(hist_notif, timeout_ms=0) # Use historical notification object
479474
hist_box.uuid = hist_notif.id # Assign UUID to hist_box as well
480475
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
481477
# Action buttons are removed as they are not necessary in history
482478
for child in hist_box.get_children():
483479
if child.get_name() == "notification-action-buttons":
@@ -488,6 +484,7 @@ def _add_historical_notification(self, note):
488484
h_align="fill",
489485
h_expand=True,
490486
)
487+
container.notification_box = hist_box # Store notification_box in container
491488
# Convert the timestamp to a datetime object; if it fails, datetime.now() is used
492489
try:
493490
arrival = datetime.fromisoformat(hist_notif.timestamp)
@@ -592,29 +589,27 @@ def add_notification(self, notification_box):
592589
oldest_notification_container = self.notifications_list.get_children()[0]
593590
self.notifications_list.remove(oldest_notification_container)
594591
# 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):
596593
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}")
599596
except Exception as e:
600597
logger.error(f"Error deleting cached image of oldest notification: {e}")
601598
oldest_notification_container.destroy() # Destroy the container as well
602599

603-
# Cache the image when adding to history
604-
if notification_box.notification.image_pixbuf:
605-
cache_notification_pixbuf(notification_box)
606600

607601
def on_container_destroy(container):
608602
if hasattr(container, "_timestamp_timer_id") and container._timestamp_timer_id:
609603
GLib.source_remove(container._timestamp_timer_id)
610604
if hasattr(container, "notification_box"): # Use container.notification_box
611605
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}")
618613
container.destroy()
619614
GLib.idle_add(self.update_separators)
620615
self.update_no_notifications_label_visibility() # Update label visibility after removing
@@ -839,16 +834,15 @@ def on_new_notification(self, fabric_notif, id):
839834
notification = fabric_notif.get_notification_from_id(id)
840835
new_box = NotificationBox(notification)
841836
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
843838
# Do NOT set container or connect closed signal as it's for history only
844839
self.notch.notification_history.add_notification(new_box) # Directly add to history
845840
return # Exit early, do not proceed with displaying live notification
846841

847842
notification = fabric_notif.get_notification_from_id(id)
848843
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
852846
new_box.set_container(self)
853847
notification.connect("closed", self.on_notification_closed)
854848
while len(self.notifications) >= 5:
@@ -888,17 +882,19 @@ def on_notification_closed(self, notification, reason):
888882
return
889883
i, notif_box = notif_to_remove
890884
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
900893
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
902898

903899
if len(self.notifications) == 1:
904900
self._is_destroying = True
@@ -929,6 +925,7 @@ def _destroy_container(self):
929925
self.notifications.clear()
930926
self._destroyed_notifications.clear()
931927
for child in self.stack.get_children():
928+
child.destroy() # Destroy each child (NotificationBox) properly
932929
self.stack.remove(child)
933930
self.current_index = 0
934931
self.navigation.set_visible(False)

0 commit comments

Comments
 (0)