Initial commit: Bifrost accessible fediverse client

- Full ActivityPub support for Pleroma, GoToSocial, and Mastodon
- Screen reader optimized interface with PySide6
- Timeline switching with tabs and keyboard shortcuts (Ctrl+1-4)
- Threaded conversation navigation with expand/collapse
- Cross-platform desktop notifications via plyer
- Customizable sound pack system with audio feedback
- Complete keyboard navigation and accessibility features
- XDG Base Directory compliant configuration
- Multiple account support with OAuth authentication

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Storm Dragon
2025-07-20 03:39:47 -04:00
commit 460dfc52a5
31 changed files with 5320 additions and 0 deletions

View File

@ -0,0 +1,109 @@
"""
Desktop notification manager using plyer
"""
from typing import Optional
from plyer import notification
from config.settings import SettingsManager
class NotificationManager:
"""Manages desktop notifications for Bifrost"""
def __init__(self, settings: SettingsManager):
self.settings = settings
def is_enabled(self, notification_type: str = None) -> bool:
"""Check if notifications are enabled globally or for specific type"""
if not self.settings.get_bool('notifications', 'enabled', True):
return False
if notification_type:
return self.settings.get_bool('notifications', notification_type, True)
return True
def show_notification(self, title: str, message: str, notification_type: str = None):
"""Show a desktop notification"""
if not self.is_enabled(notification_type):
return
try:
notification.notify(
title=title,
message=message,
app_name="Bifrost",
timeout=5
)
except Exception as e:
print(f"Failed to show notification: {e}")
def notify_direct_message(self, sender: str, message_preview: str):
"""Show notification for direct message"""
if not self.is_enabled('direct_messages'):
return
self.show_notification(
title=f"Direct message from {sender}",
message=message_preview,
notification_type='direct_messages'
)
def notify_mention(self, sender: str, post_preview: str):
"""Show notification for mention"""
if not self.is_enabled('mentions'):
return
self.show_notification(
title=f"{sender} mentioned you",
message=post_preview,
notification_type='mentions'
)
def notify_boost(self, sender: str, post_preview: str):
"""Show notification for boost/reblog"""
if not self.is_enabled('boosts'):
return
self.show_notification(
title=f"{sender} boosted your post",
message=post_preview,
notification_type='boosts'
)
def notify_favorite(self, sender: str, post_preview: str):
"""Show notification for favorite"""
if not self.is_enabled('favorites'):
return
self.show_notification(
title=f"{sender} favorited your post",
message=post_preview,
notification_type='favorites'
)
def notify_follow(self, follower: str):
"""Show notification for new follower"""
if not self.is_enabled('follows'):
return
self.show_notification(
title="New follower",
message=f"{follower} started following you",
notification_type='follows'
)
def notify_timeline_update(self, count: int, timeline_type: str = "timeline"):
"""Show notification for timeline updates"""
if not self.is_enabled('timeline_updates'):
return
if count == 1:
message = f"1 new post in your {timeline_type}"
else:
message = f"{count} new posts in your {timeline_type}"
self.show_notification(
title="Timeline updated",
message=message,
notification_type='timeline_updates'
)