Fix notification for same attibutes

This commit is contained in:
tr1x_em committed 2025-08-14 16:05:29 +05:30
1 parent 1fbbe74520
commit ac484bc682
2 files changed
+154 -158

No files matched your search

+97 -135
View File
@@ -65,65 +65,6 @@ class ExpandableNotificationGroup(Box):
notification_widget = NotificationCenterWidget(
notification=latest_notification
)
# single_notification = Box(
# name="single-notification-content",
# spacing=8,
# children=[
# Box(
# name="notification-image",
# children=CustomImage(
# pixbuf=self._get_notification_pixbuf(
# latest_notification._notification
# )
# ),
# ),
# Box(
# name="notification-text",
# orientation="v",
# v_align="center",
# h_expand=True,
# children=[
# Box(
# name="notification-summary-box",
# orientation="h",
# children=[
# Label(
# name="notification-summary",
# markup=f"<b>{self.app_name}</b>",
# h_align="start",
# ellipsization="end",
# ),
# ],
# ),
# Label(
# name="notification-body",
# markup=latest_notification._notification.summary.replace(
# "\n", " "
# ),
# max_chars_width=35,
# h_align="start",
# ellipsization="end",
# ),
# ],
# ),
# Box(
# orientation="v",
# children=[
# Button(
# name="notification-close",
# image=CustomImage(
# icon_name="close-symbolic", icon_size=18
# ),
# visible=True,
# on_clicked=lambda *_: self._close_single_notification_and_stop_propagation(
# latest_notification
# ),
# ),
# Box(v_expand=True),
# ],
# ),
# ],
# )
self.collapsed_eventbox.add(notification_widget)
else:
# Multiple notifications - create stacked effect
@@ -138,7 +79,6 @@ class ExpandableNotificationGroup(Box):
if num_notifications >= 3:
bottom_shadow = Box(
name="stack-shadow-bottom",
# style="min-height: 16px; margin-left: 20px; margin-right: -4px; margin-bottom: -8px;",
)
stack_container.add(bottom_shadow)
@@ -146,7 +86,6 @@ class ExpandableNotificationGroup(Box):
if num_notifications >= 2:
middle_shadow = Box(
name="stack-shadow-middle",
# style="min-height: 20px; margin-left: 10px; margin-right: -2px; margin-bottom: -12px;",
)
stack_container.add(middle_shadow)
@@ -158,8 +97,8 @@ class ExpandableNotificationGroup(Box):
Box(
name="notification-image",
children=CustomImage(
pixbuf=self._get_notification_pixbuf(
latest_notification._notification
pixbuf=self._get_notification_pixbuf_for_group(
latest_notification
)
),
),
@@ -223,6 +162,51 @@ class ExpandableNotificationGroup(Box):
# Create expanded state (hidden initially)
self.create_expanded_state()
def _get_notification_pixbuf_for_group(self, cached_notification):
"""Get notification pixbuf using cached image key - fallback to app icon"""
notification = cached_notification._notification
notification_id = getattr(notification, "id", None)
# First try to get cached notification image using stored cache key
if hasattr(cached_notification, 'cache_metadata') and cached_notification.cache_metadata:
notification_image_cache_key = cached_notification.cache_metadata.get('notification_image_cache_key')
if notification_image_cache_key:
try:
cached_image = get_cached_notification_image(notification_image_cache_key)
if cached_image:
logger.debug(f"Using cached notification image: {notification_image_cache_key}")
return cached_image
except Exception as e:
logger.debug(f"Failed to load cached notification image: {e}")
# Fallback to app icon using cached key
if hasattr(cached_notification, 'cache_metadata') and cached_notification.cache_metadata:
app_icon_cache_key = cached_notification.cache_metadata.get('app_icon_cache_key')
if app_icon_cache_key:
try:
from modules.notification.unified_cache import get_from_cache
cached_app_icon = get_from_cache(app_icon_cache_key, (35, 35))
if cached_app_icon:
logger.debug(f"Using cached app icon: {app_icon_cache_key}")
return cached_app_icon
except Exception as e:
logger.debug(f"Failed to load cached app icon: {e}")
# Final fallback - try to cache app icon directly if available
try:
app_icon_source = getattr(notification, "app_icon", None)
if app_icon_source:
cached_app_icon = cache_notification_icon(app_icon_source, (35, 35))
if cached_app_icon:
logger.debug(f"Using directly cached app icon for: {app_icon_source}")
return cached_app_icon
except Exception as e:
logger.debug(f"Failed to get directly cached app icon: {e}")
# Ultimate fallback
logger.debug("Using fallback notification icon")
return get_fallback_notification_icon((35, 35))
def create_expanded_state(self):
# Create main expanded container
self.expanded_container = Box(
@@ -310,62 +294,6 @@ class ExpandableNotificationGroup(Box):
# Hide the entire expanded container initially
self.expanded_container.set_visible(False)
def _get_notification_pixbuf(self, notification):
"""Simplified notification pixbuf for notification center"""
notification_id = getattr(notification, "id", None)
try:
# Try to process current pixbuf if available
if hasattr(notification, "image_pixbuf") and notification.image_pixbuf:
try:
cache_key = get_notification_image_cache_key(
notification_id, notification.image_pixbuf
)
cached_image = get_cached_notification_image(cache_key)
if cached_image:
logger.debug(f"Using cached notification image: {cache_key}")
return cached_image
# Try to cache the image now
cache_path, cache_key = cache_notification_image(
notification_id, notification.image_pixbuf, (35, 35)
)
if cache_path and cache_key:
cached_pixbuf = get_cached_notification_image(cache_key)
if cached_pixbuf:
logger.debug(
f"Cached and using notification image: {cache_key}"
)
return cached_pixbuf
# Direct fallback if caching succeeded but loading failed
logger.debug("Using direct scaling for notification image")
return notification.image_pixbuf.scale_simple(
35, 35, GdkPixbuf.InterpType.BILINEAR
)
except Exception as image_error:
logger.debug(f"Notification image processing failed: {image_error}")
# Continue to app icon fallback
except Exception as e:
logger.debug(f"Failed to process notification image: {e}")
# Use cached app icon as fallback
try:
app_icon_source = getattr(notification, "app_icon", None)
if app_icon_source:
cached_app_icon = cache_notification_icon(app_icon_source, (35, 35))
if cached_app_icon:
logger.debug(f"Using cached app icon for: {app_icon_source}")
return cached_app_icon
except Exception as e:
logger.debug(f"Failed to get cached app icon: {e}")
# Ultimate fallback
logger.debug("Using fallback notification icon")
return get_fallback_notification_icon((35, 35))
def on_clicked(self, widget, event):
if event.button == 1: # Left click
# Always allow expansion, even for single notifications
@@ -505,6 +433,7 @@ class ExpandableNotificationGroup(Box):
class NotificationCenterWidget(NotificationWidget):
def __init__(self, notification, **kwargs):
self.notification_id = notification.cache_id
self.cache_metadata = getattr(notification, 'cache_metadata', {})
super().__init__(
notification._notification,
@@ -514,6 +443,50 @@ class NotificationCenterWidget(NotificationWidget):
**kwargs,
)
def _get_notification_pixbuf(self, notification):
"""Get notification pixbuf using cached image key - fallback to app icon"""
notification_id = getattr(notification, "id", None)
# First try to get cached notification image using stored cache key
if self.cache_metadata:
notification_image_cache_key = self.cache_metadata.get('notification_image_cache_key')
if notification_image_cache_key:
try:
cached_image = get_cached_notification_image(notification_image_cache_key)
if cached_image:
logger.debug(f"Using cached notification image: {notification_image_cache_key}")
return cached_image
except Exception as e:
logger.debug(f"Failed to load cached notification image: {e}")
# Fallback to app icon using cached key
if self.cache_metadata:
app_icon_cache_key = self.cache_metadata.get('app_icon_cache_key')
if app_icon_cache_key:
try:
from modules.notification.unified_cache import get_from_cache
cached_app_icon = get_from_cache(app_icon_cache_key, (35, 35))
if cached_app_icon:
logger.debug(f"Using cached app icon: {app_icon_cache_key}")
return cached_app_icon
except Exception as e:
logger.debug(f"Failed to load cached app icon: {e}")
# Final fallback - try to cache app icon directly if available
try:
app_icon_source = getattr(notification, "app_icon", None)
if app_icon_source:
cached_app_icon = cache_notification_icon(app_icon_source, (35, 35))
if cached_app_icon:
logger.debug(f"Using directly cached app icon for: {app_icon_source}")
return cached_app_icon
except Exception as e:
logger.debug(f"Failed to get directly cached app icon: {e}")
# Ultimate fallback
logger.debug("Using fallback notification icon")
return get_fallback_notification_icon((35, 35))
def create_content(self, notification):
# Create our custom close button for notification center
@@ -594,10 +567,8 @@ class NotificationCenterWidget(NotificationWidget):
def _on_close_clicked(self, *args):
try:
# Get notification cache metadata for cleanup
cache_metadata = getattr(self, "cache_metadata", {})
if hasattr(self.notification, "_cache_metadata"):
cache_metadata = self.notification._cache_metadata
# Use instance cache metadata instead of notification attribute
cache_metadata = self.cache_metadata
# Clean up caches using stored metadata
from modules.notification.notification import (
@@ -629,7 +600,7 @@ class NotificationCenterWidget(NotificationWidget):
# Override to disable auto-close functionality
def close_notification(self):
pass
return False
class NotificationCenter(Window):
@@ -919,14 +890,5 @@ class NotificationCenter(Window):
logger.debug(f"Notification center visibility set to: {visible}")
def _on_destroy(self, *_):
try:
notification_service.disconnect(
"cached-notification-added", self.on_notification_added
)
notification_service.disconnect(
"cached-notification-removed", self.on_notification_removed
)
notification_service.disconnect("clear-all", self.on_clear_all)
notification_service.disconnect("notify::count", self.on_count_changed)
except Exception as e:
logger.error(f"Error disconnecting signals: {e}")
# Signals will be automatically disconnected when the object is destroyed
pass
+57 -23
View File
@@ -92,19 +92,23 @@ class CachedNotification(Service):
@Property(object, "readable")
def image_pixbuf(self) -> GdkPixbuf.Pixbuf | None:
if self.image_pixmap:
return self.image_pixmap.as_pixbuf()
if self.image_file and os.path.exists(self.image_file):
try:
return GdkPixbuf.Pixbuf.new_from_file(self.image_file)
except Exception:
# If file can't be loaded, return None
pass
try:
if self.image_pixmap:
return self.image_pixmap.as_pixbuf()
if self.image_file and os.path.exists(self.image_file):
try:
return GdkPixbuf.Pixbuf.new_from_file(self.image_file)
except Exception:
# If file can't be loaded, return None
pass
except Exception:
# If any error occurs (including temp file gone), return None safely
pass
return None
@Property(dict, "readable")
def serialized(self) -> dict:
"""Enhanced serialization with cache metadata"""
"""Enhanced serialization with cache metadata - stores only cache keys"""
from modules.notification.notification import (
get_cache_key,
get_notification_image_cache_key,
@@ -117,17 +121,27 @@ class CachedNotification(Service):
if self.app_icon:
app_icon_cache_key = get_cache_key(self.app_icon, (35, 35), self.app_name)
if self.id and hasattr(self._notification, 'image_pixbuf'):
# Only try to access image_pixbuf if we can safely do so
# Only try to get notification image cache key if we can safely access image_pixbuf
if self.id:
try:
# Check if image_pixbuf exists and can be accessed
image_pixbuf = getattr(self._notification, 'image_pixbuf', None)
if image_pixbuf:
notification_image_cache_key = get_notification_image_cache_key(
self.id, image_pixbuf
)
except (AttributeError, OSError, Exception):
# If temp file is gone or any other error, just mark as None
# First check if we already have the cache key stored
if hasattr(self, 'cache_metadata') and self.cache_metadata:
notification_image_cache_key = self.cache_metadata.get('notification_image_cache_key')
# If not, try to generate it safely
if not notification_image_cache_key and hasattr(self._notification, 'image_pixbuf'):
try:
# Check if image_pixbuf exists and can be accessed without loading from file
image_pixbuf = getattr(self._notification, 'image_pixbuf', None)
if image_pixbuf:
notification_image_cache_key = get_notification_image_cache_key(
self.id, image_pixbuf
)
except (AttributeError, OSError, Exception):
# If temp file is gone or any other error, just mark as None
pass
except Exception:
# If any error occurs during cache key generation, skip it
pass
return {
@@ -141,12 +155,11 @@ class CachedNotification(Service):
"urgency": self.urgency,
"actions": [(action.identifier, action.label) for action in self.actions],
"image-file": self.image_file,
"image-pixmap": (
self.image_pixmap.serialize() if self.image_pixmap else None
),
# Only store image-pixmap if no cache key is available (fallback)
"image-pixmap": None, # Don't store image data, only cache key
"timestamp": int(time.time()),
"group": self.app_name, # Group notifications by app name
# Enhanced cache metadata
# Enhanced cache metadata - store only cache keys
"cache_metadata": {
"app_icon_cache_key": app_icon_cache_key,
"notification_image_cache_key": notification_image_cache_key,
@@ -284,6 +297,9 @@ class CachedNotifications(Notifications):
"""Handle notification added and cache it with enhanced metadata"""
# Don't call super() - we're handling this ourselves
# Import logger at the top of the function
from loguru import logger
notification = self.get_notification_from_id(notification_id)
if notification:
@@ -300,8 +316,22 @@ class CachedNotifications(Notifications):
# Check if this app should be ignored for history (don't cache)
if notification.app_name in data.NOTIFICATION_IGNORED_APPS_HISTORY:
# Don't cache notifications from ignored apps, but still allow popup display
logger.debug(f"Ignoring notification from {notification.app_name} (in ignore list)")
return
# Check if we already have this notification cached (by notification.id)
existing_notification = None
for cached_notif in self._cached_notifications.values():
if cached_notif._notification.id == notification.id:
existing_notification = cached_notif
break
if existing_notification:
logger.debug(f"Notification ID {notification.id} already cached, skipping")
return
logger.debug(f"Caching new notification: ID={notification.id}, App={notification.app_name}, Summary={notification.summary[:50]}...")
# Cache notifications (except for ignored apps)
# DND only affects popup display, not caching
cache_id = self._next_cache_id
@@ -357,6 +387,10 @@ class CachedNotifications(Notifications):
self.notify("count")
self.emit("cached-notification-added", cached_notification)
logger.debug(f"Successfully cached notification: Cache ID={cache_id}, Total cached={len(self._cached_notifications)}")
else:
print(f"WARNING: Failed to get notification with ID {notification_id}")
def remove_cached_notification(self, notification_id: int):
"""Remove the notification of given id with enhanced cache cleanup"""