Smooth notification + Removing logs

This commit is contained in:
tr1x_em committed 2025-08-07 11:21:36 +05:30
1 parent fb65e0b55d
commit da03fcd84e
2 files changed
+115 -50

No files matched your search

+2
View File
@@ -21,6 +21,8 @@ for log in [
"fabric.bluetooth.service", "fabric.bluetooth.service",
"services.network", "services.network",
"utils.wayland", "utils.wayland",
"modules.notification.notification",
"modules.notification.notification_center",
]: ]:
logger.disable(log) logger.disable(log)
+113 -50
View File
@@ -328,8 +328,8 @@ ensure_notification_cache_dirs()
cleanup_old_cache_files() cleanup_old_cache_files()
def smooth_revealer_animation(revealer: SlideRevealer, duration: int = 350): def smooth_revealer_animation(revealer: SlideRevealer, duration: int = 280):
"""Configure revealer for macOS-like smooth animation""" """Configure revealer for ultra-smooth animation"""
revealer.duration = duration revealer.duration = duration
@@ -691,7 +691,7 @@ class NotificationRevealer(SlideRevealer):
super().__init__( super().__init__(
child=self.event_box, child=self.event_box,
direction="right", direction="right",
duration=600, # Optimized duration for macOS-like feel duration=280, # Faster, smoother duration
) )
smooth_revealer_animation(self) smooth_revealer_animation(self)
@@ -701,16 +701,47 @@ class NotificationRevealer(SlideRevealer):
self._animation_in_progress = True self._animation_in_progress = True
def _ease_out_back(self, t): def _ease_out_cubic(self, t):
"""Easing function for spring-back animation""" """Smoother easing function for better animation quality"""
c1 = 1.70158 return 1 - pow(1 - t, 3)
c3 = c1 + 1
return 1 + c3 * pow(t - 1, 3) + c1 * pow(t - 1, 2) def _ease_out_quart(self, t):
"""Even smoother easing for ultra-smooth animations"""
return 1 - pow(1 - t, 4)
def _apply_transform(self, offset_x, opacity, scale):
"""Apply smooth CSS transforms for animation"""
try:
# Create CSS transformation
transform_css = f"""
opacity: {opacity};
transform: translateX({offset_x}px) scale({scale});
transition: none;
"""
# Apply to the notification box
if hasattr(self.notif_box, 'get_style_context'):
style_context = self.notif_box.get_style_context()
if style_context:
# Use CSS provider for smooth transforms
if not hasattr(self, '_css_provider') or not self._css_provider:
from gi.repository import Gtk
self._css_provider = Gtk.CssProvider()
style_context.add_provider(
self._css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
css_data = f"* {{ {transform_css} }}"
self._css_provider.load_from_data(css_data.encode())
except Exception as e:
logger.debug(f"Transform apply failed (non-critical): {e}")
def _animate_dismiss(self, start_offset): def _animate_dismiss(self, start_offset):
"""Animate the notification sliding out completely - now much faster""" """Animate the notification sliding out with smooth 60fps animation"""
target_offset = NOTIFICATION_WIDTH + 50 # Slide completely out of view target_offset = NOTIFICATION_WIDTH + 50
duration = 120 # Much faster dismiss animation (was 250) duration = 200 # Slightly longer for smoother feel
if self._spring_timer_id: if self._spring_timer_id:
GLib.source_remove(self._spring_timer_id) GLib.source_remove(self._spring_timer_id)
@@ -723,22 +754,19 @@ class NotificationRevealer(SlideRevealer):
elapsed = current_time - start_time elapsed = current_time - start_time
progress = min(1.0, elapsed / duration) progress = min(1.0, elapsed / duration)
# Use faster easing for snappier exit # Use smoother easing for premium feel
eased_progress = ( eased_progress = self._ease_out_quart(progress)
progress * progress
) # Quadratic ease out - faster than cubic
current_offset = start_offset + (offset_diff * eased_progress) current_offset = start_offset + (offset_diff * eased_progress)
# Fade out and scale down during dismiss # Smoother fade and scale transitions
opacity = 1.0 - (progress * 1.2) # Faster fade out opacity = max(0.0, 1.0 - (progress * 0.9)) # Gentler fade
scale = 1.0 - (progress * 0.15) # Slightly more scale change scale = max(0.9, 1.0 - (progress * 0.1)) # Subtle scale
self._apply_transform(current_offset, opacity, scale) self._apply_transform(current_offset, opacity, scale)
if progress >= 1.0: if progress >= 1.0:
# Mark notification for cache cleanup on swipe dismissal # Mark notification for cache cleanup on swipe dismissal
self.notif_box._should_cleanup_cache = True self.notif_box._should_cleanup_cache = True
# Trigger the actual notification dismissal immediately
try: try:
self.notification.close("dismissed-by-user") self.notification.close("dismissed-by-user")
except: except:
@@ -747,10 +775,11 @@ class NotificationRevealer(SlideRevealer):
return True return True
# Use consistent 60fps timing
self._animation_in_progress = True self._animation_in_progress = True
self._spring_timer_id = GLib.timeout_add( self._spring_timer_id = GLib.timeout_add(
12, animate_step 16, animate_step # ~60 FPS
) # Higher fps for smoother animation )
def _calculate_drag_velocity(self, current_x): def _calculate_drag_velocity(self, current_x):
"""Calculate the velocity of the drag gesture""" """Calculate the velocity of the drag gesture"""
@@ -789,20 +818,21 @@ class NotificationRevealer(SlideRevealer):
# Use different slide directions based on dismiss reason # Use different slide directions based on dismiss reason
if reason == "expired": if reason == "expired":
# Left-to-right slide for auto-dismiss (expired) # Gentle fade-out for auto-dismiss
self.set_slide_direction("left") self.set_slide_direction("left")
self.duration = 250 # Slightly slower for natural feel
elif self._swipe_in_progress: elif self._swipe_in_progress:
# For swipe dismissals, use immediate hiding without additional slide animation # Quick slide for swipe dismissals
# The swipe animation already handled the visual feedback self.duration = 150
self.duration = 50 # Very fast transition
self.set_slide_direction("right") self.set_slide_direction("right")
else: else:
# Right-to-left slide for manual close (button clicks) # Smooth slide for manual close
self.set_slide_direction("right") self.set_slide_direction("right")
self.duration = 200
self.hide() self.hide()
# Reduced timeout for snappier transitions, especially for swipe dismissals # Consistent timing for smooth transitions
timeout_duration = 80 if self._swipe_in_progress else (self.duration + 30) timeout_duration = self.duration + 50
GLib.timeout_add(timeout_duration, lambda: self._on_animation_complete(True)) GLib.timeout_add(timeout_duration, lambda: self._on_animation_complete(True))
def destroy(self): def destroy(self):
@@ -816,6 +846,7 @@ class NotificationState:
IDLE = 0 IDLE = 0
SHOWING = 1 SHOWING = 1
HIDING = 2 HIDING = 2
TRANSITIONING = 3 # New state for smooth transitions
class ModusNoti(Window): class ModusNoti(Window):
@@ -830,11 +861,18 @@ class ModusNoti(Window):
spacing=5, spacing=5,
) )
# Enhanced queue system for smooth transitions # Enhanced queue system for ultra-smooth transitions
self.notification_queue = [] self.notification_queue = []
self.current_notification = None self.current_notification = None
self.notification_state = NotificationState.IDLE self.notification_state = NotificationState.IDLE
self._transition_timer_id = None self._transition_timer_id = None
self._debounce_timer_id = None
self._last_notification_time = 0
# Queue management settings for smooth behavior
self.MAX_QUEUE_SIZE = 3 # Limit queue to prevent overwhelming
self.TRANSITION_DELAY = 100 # Smoother transition timing
self.DEBOUNCE_DELAY = 50 # Prevent rapid fire notifications
# Initialize ignored apps list from config # Initialize ignored apps list from config
self.ignored_apps = data.NOTIFICATION_IGNORED_APPS self.ignored_apps = data.NOTIFICATION_IGNORED_APPS
@@ -861,19 +899,36 @@ class ModusNoti(Window):
# Notification is already cached by the service, just don't show popup # Notification is already cached by the service, just don't show popup
return return
# Clear any pending notifications in queue (except the current one being shown) # Implement smart queue management for smooth transitions
for pending_notification in list(self.notification_queue): current_time = GLib.get_monotonic_time() / 1000
try:
pending_notification.close("dismissed-by-user") # If queue is getting full, remove oldest notifications smoothly
except: if len(self.notification_queue) >= self.MAX_QUEUE_SIZE:
pass # Remove oldest notification from queue (not current showing one)
self.notification_queue.clear() if self.notification_queue:
oldest = self.notification_queue.pop(0)
try:
oldest.close("dismissed-by-user")
except:
pass
# Add new notification to queue # Add new notification to queue
self.notification_queue.append(notification) self.notification_queue.append(notification)
# Process the queue # Debounce rapid notifications for smoother experience
if self._debounce_timer_id:
GLib.source_remove(self._debounce_timer_id)
self._debounce_timer_id = GLib.timeout_add(
self.DEBOUNCE_DELAY,
lambda: self._process_notification_queue_debounced() or False
)
def _process_notification_queue_debounced(self):
"""Process queue after debounce delay for smooth transitions"""
self._debounce_timer_id = None
self._process_notification_queue() self._process_notification_queue()
return False
def _process_notification_queue(self): def _process_notification_queue(self):
# If we're currently showing a notification and there's a new one in queue # If we're currently showing a notification and there's a new one in queue
@@ -882,8 +937,9 @@ class ModusNoti(Window):
and self.current_notification and self.current_notification
and self.notification_queue and self.notification_queue
): ):
# Start hiding the current notification to make room for the new one # Smooth transition: start hiding current notification
self._start_hiding_current_notification() self.notification_state = NotificationState.TRANSITIONING
self._start_smooth_transition()
elif ( elif (
self.notification_state == NotificationState.IDLE self.notification_state == NotificationState.IDLE
@@ -892,20 +948,21 @@ class ModusNoti(Window):
# If we're idle and have notifications in queue, show the next one # If we're idle and have notifications in queue, show the next one
self._show_next_notification() self._show_next_notification()
def _start_hiding_current_notification(self): def _start_smooth_transition(self):
"""Start smooth transition between notifications"""
if ( if (
self.current_notification self.current_notification
and self.notification_state == NotificationState.SHOWING
and not self.current_notification._is_closing and not self.current_notification._is_closing
): ):
self.notification_state = NotificationState.HIDING # Don't mark for cache cleanup during smooth transitions
# to maintain performance
# Mark for cache cleanup when forcibly hiding for new notification # Use shorter timeout for smooth transitions
self.current_notification.notif_box._should_cleanup_cache = True self.current_notification.notif_box.timeout_ms = 100
# Force close the current notification to trigger hiding animation # Force close current notification with smooth animation
try: try:
self.current_notification.notification.close("dismissed-by-user") self.current_notification.notification.close("expired")
except: except:
pass pass
@@ -966,10 +1023,10 @@ class ModusNoti(Window):
self.current_notification = None self.current_notification = None
self.notification_state = NotificationState.IDLE self.notification_state = NotificationState.IDLE
# Process next notification with a small delay for smooth transitions # Process next notification with optimized delay for ultra-smooth transitions
if self.notification_queue: if self.notification_queue:
self._transition_timer_id = GLib.timeout_add( self._transition_timer_id = GLib.timeout_add(
50, # Very short delay for seamless transitions self.TRANSITION_DELAY, # Consistent smooth timing
lambda: self._show_next_notification() or False, lambda: self._show_next_notification() or False,
) )
@@ -982,13 +1039,15 @@ class ModusNoti(Window):
self._on_notification_finished(notification_box) self._on_notification_finished(notification_box)
def clear_notification_queue(self): def clear_notification_queue(self):
"""Clear queue with smooth cleanup"""
queue_length = len(self.notification_queue) queue_length = len(self.notification_queue)
if queue_length > 0: if queue_length > 0:
# Smooth dismissal of queued notifications
for notification in list(self.notification_queue): for notification in list(self.notification_queue):
try: try:
notification.close("dismissed-by-user") notification.close("dismissed-by-user")
except: except:
pass # Ignore errors if notification is already closed pass
self.notification_queue.clear() self.notification_queue.clear()
# Also clean current notification if showing # Also clean current notification if showing
@@ -996,10 +1055,14 @@ class ModusNoti(Window):
# Mark for cache cleanup when clearing queue # Mark for cache cleanup when clearing queue
self.current_notification.notif_box._should_cleanup_cache = True self.current_notification.notif_box._should_cleanup_cache = True
# Cancel any pending transition timer # Clear animation timers
if self._transition_timer_id: if self._transition_timer_id:
GLib.source_remove(self._transition_timer_id) GLib.source_remove(self._transition_timer_id)
self._transition_timer_id = None self._transition_timer_id = None
if self._debounce_timer_id:
GLib.source_remove(self._debounce_timer_id)
self._debounce_timer_id = None
def get_queue_length(self): def get_queue_length(self):
return len(self.notification_queue) return len(self.notification_queue)