✨ feat(notification): implement notification center with persistent storage and DND support
This commit is contained in:
15 files changed
+1260
-472
No files matched your search
@@ -15,10 +15,10 @@ from widgets.mousecapture import DropDownMouseCapture
|
||||
|
||||
class AppName:
|
||||
def __init__(self, path="/usr/share/applications"):
|
||||
self.files = os.listdir(path) if os.path.exists(path) else []
|
||||
self.files = os.listdir(path)
|
||||
self.path = path
|
||||
|
||||
def get_app_name(self, wmclass):
|
||||
def get_app_name(self, wmclass, format_=False):
|
||||
desktop_file = ""
|
||||
for f in self.files:
|
||||
if f.startswith(wmclass + ".desktop"):
|
||||
@@ -28,17 +28,39 @@ class AppName:
|
||||
|
||||
if desktop_file == "":
|
||||
return wmclass
|
||||
try:
|
||||
with open(os.path.join(self.path, desktop_file), "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line.startswith("Name="):
|
||||
desktop_app_name = line.split("=")[1].strip()
|
||||
break
|
||||
except:
|
||||
return wmclass
|
||||
with open(os.path.join(self.path, desktop_file), "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line.startswith("Name="):
|
||||
desktop_app_name = line.split("=")[1].strip()
|
||||
break
|
||||
return desktop_app_name
|
||||
|
||||
def get_app_exec(self, wmclass, format_=False):
|
||||
desktop_file = ""
|
||||
for f in self.files:
|
||||
if f.startswith(wmclass + ".desktop"):
|
||||
desktop_file = f
|
||||
|
||||
desktop_app_name = wmclass
|
||||
|
||||
if desktop_file == "":
|
||||
return wmclass
|
||||
with open(os.path.join(self.path, desktop_file), "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line.startswith("Exec="):
|
||||
desktop_app_name = line.split("=")[1].strip()
|
||||
break
|
||||
return desktop_app_name
|
||||
|
||||
def get_desktop_file(self, wmclass):
|
||||
desktop_file = ""
|
||||
for f in self.files:
|
||||
if f.startswith(wmclass + ".desktop"):
|
||||
desktop_file = f
|
||||
return desktop_file
|
||||
|
||||
def format_app_name(self, title, wmclass, update=False):
|
||||
name = wmclass
|
||||
if name == "":
|
||||
@@ -62,8 +84,6 @@ app_name_class = AppName()
|
||||
|
||||
def format_window(title, wmclass):
|
||||
name = app_name_class.format_app_name(title, wmclass, True)
|
||||
if not name or name == "":
|
||||
return "Desktop"
|
||||
return name
|
||||
|
||||
|
||||
@@ -263,10 +283,11 @@ class MenuBarDropdowns:
|
||||
"label", f"About {value}"
|
||||
),
|
||||
)
|
||||
|
||||
self.global_menu_button_title = Button(
|
||||
child=ActiveWindow(
|
||||
formatter=FormattedString(
|
||||
"{ format_window('None', 'Hyprland') if win_title == '' and win_class == '' else format_window(win_title, win_class) }",
|
||||
"{ format_window(win_title, win_class) if win_title or win_class else 'Hyprland' }",
|
||||
format_window=format_window,
|
||||
)
|
||||
),
|
||||
@@ -274,6 +295,7 @@ class MenuBarDropdowns:
|
||||
style_classes="button",
|
||||
on_clicked=lambda _: self.global_menu_title.toggle_mousecapture(),
|
||||
)
|
||||
|
||||
self.global_menu_title.child_window.set_pointing_to(
|
||||
self.global_menu_button_title
|
||||
)
|
||||
|
||||
+51
-3
@@ -7,6 +7,7 @@ from fabric.widgets.datetime import DateTime
|
||||
from fabric.widgets.revealer import Revealer
|
||||
from fabric.widgets.svg import Svg
|
||||
from modules.controlcenter.main import ModusControlCenter
|
||||
from modules.notification.notification_center import NotificationCenter
|
||||
from modules.panel.components.enhanced_system_tray import apply_enhanced_system_tray
|
||||
from modules.panel.components.indicators import (
|
||||
BatteryIndicator,
|
||||
@@ -15,6 +16,7 @@ from modules.panel.components.indicators import (
|
||||
)
|
||||
from modules.panel.components.menubar import MenuBar
|
||||
from modules.panel.components.recording_indicator import RecordingIndicator
|
||||
from utils.roam import modus_service
|
||||
from widgets.mousecapture import MouseCapture
|
||||
from widgets.wayland import WaylandWindow as Window
|
||||
|
||||
@@ -39,12 +41,27 @@ class Panel(Window):
|
||||
self.imac = Button(
|
||||
name="panel-button",
|
||||
child=Svg(
|
||||
size=22,
|
||||
size=28,
|
||||
svg_file=get_relative_path("../../config/assets/icons/misc/logo.svg"),
|
||||
),
|
||||
on_clicked=lambda *_: self.menubar.show_system_dropdown(self.imac),
|
||||
)
|
||||
|
||||
# DND indicator
|
||||
self.dnd_icon = Svg(
|
||||
size=34,
|
||||
svg_file=get_relative_path(
|
||||
"../../config/assets/icons/applets/dnd-clear.svg"
|
||||
),
|
||||
)
|
||||
|
||||
self.dnd_indicator = Button(
|
||||
name="dnd-indicator",
|
||||
child=self.dnd_icon,
|
||||
style="opacity: 0.2;",
|
||||
visible=True,
|
||||
)
|
||||
|
||||
self.tray = SystemTray(name="system-tray", spacing=4, icon_size=20)
|
||||
|
||||
self.tray_revealer = Revealer(
|
||||
@@ -81,7 +98,7 @@ class Panel(Window):
|
||||
name="panel-button",
|
||||
on_clicked=lambda *_: self.search_apps(),
|
||||
child=Svg(
|
||||
size=20,
|
||||
size=22,
|
||||
svg_file=get_relative_path("../../config/assets/icons/misc/search.svg"),
|
||||
),
|
||||
)
|
||||
@@ -102,6 +119,18 @@ class Panel(Window):
|
||||
),
|
||||
)
|
||||
|
||||
# Notification Center with MouseCapture
|
||||
self.notification_center = MouseCapture(
|
||||
layer="overlay", child_window=NotificationCenter()
|
||||
)
|
||||
|
||||
# Clickable DateTime for notification center
|
||||
self.datetime_button = Button(
|
||||
name="datetime-button",
|
||||
on_clicked=self.notification_center.toggle_mousecapture,
|
||||
child=DateTime(name="date-time", formatters=["%a %b %d %I:%M"]),
|
||||
)
|
||||
|
||||
self.recording_indicator = RecordingIndicator()
|
||||
|
||||
self.children = CenterBox(
|
||||
@@ -122,16 +151,22 @@ class Panel(Window):
|
||||
spacing=4,
|
||||
orientation="h",
|
||||
children=[
|
||||
self.dnd_indicator,
|
||||
self.tray_revealer,
|
||||
self.chevron_button,
|
||||
self.indicators,
|
||||
self.search,
|
||||
self.control_center_button,
|
||||
DateTime(name="date-time", formatters=["%a %b %d %I:%M"]),
|
||||
self.datetime_button,
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
# Connect to DND state changes
|
||||
modus_service.connect("dont-disturb-changed", self.on_dnd_changed)
|
||||
# Set initial DND state
|
||||
self.update_dnd_indicator(modus_service.dont_disturb)
|
||||
|
||||
return self.show_all()
|
||||
|
||||
def search_apps(self):
|
||||
@@ -149,3 +184,16 @@ class Panel(Window):
|
||||
self.chevron_button.get_child().set_from_file(
|
||||
get_relative_path("../../config/assets/icons/misc/chevron-right.svg")
|
||||
)
|
||||
|
||||
def on_dnd_changed(self, _, dnd_state):
|
||||
"""Handle DND state changes from the service."""
|
||||
self.update_dnd_indicator(dnd_state)
|
||||
|
||||
def update_dnd_indicator(self, dnd_enabled):
|
||||
"""Update the DND indicator opacity based on DND state."""
|
||||
if dnd_enabled:
|
||||
# 100% opacity when DND is enabled
|
||||
self.dnd_indicator.set_style("opacity: 1.0;")
|
||||
else:
|
||||
# 20% opacity when DND is disabled
|
||||
self.dnd_indicator.set_style("opacity: 0.2;")
|
||||
Reference in new issue
Block a user