✨ feat(dashboard): implement dashboard with notifications and keybinding
This commit is contained in:
9 files changed
+478
-126
No files matched your search
@@ -37,6 +37,8 @@ DEFAULTS = {
|
||||
"suffix_restart_inspector": "B",
|
||||
"prefix_settings": "SUPER",
|
||||
"suffix_settings": "I",
|
||||
"prefix_dashboard": "SUPER",
|
||||
"suffix_dashboard": "G",
|
||||
"wallpapers_dir": "/home/sankalp/Pictures/wallpapers",
|
||||
"vertical": True,
|
||||
"dock_enabled": True,
|
||||
|
||||
@@ -68,6 +68,7 @@ class KeyBindingsTab:
|
||||
("Kanban", "prefix_kanban", "suffix_kanban"),
|
||||
("Power Menu", "prefix_power", "suffix_power"),
|
||||
("Toggle Caffeine", "prefix_caffeine", "suffix_caffeine"),
|
||||
("Dashboard", "prefix_dashboard", "suffix_dashboard"),
|
||||
("Settings", "prefix_settings", "suffix_settings"),
|
||||
(
|
||||
"Restart with inspector",
|
||||
|
||||
@@ -282,6 +282,8 @@ bind = {bind_vars.get("prefix_power", "SUPER")}, {bind_vars.get("suffix_power",
|
||||
bind = {bind_vars.get("prefix_caffeine", "SUPER SHIFT")}, {bind_vars.get("suffix_caffeine", "M")}, exec, $fabricSend "launcher.show_launcher('caffeine on', external=True)"
|
||||
# Settings
|
||||
bind = {bind_vars.get("prefix_settings", "SUPER")}, {bind_vars.get("suffix_settings", "I")}, exec, uwsm-app $(python {home}/.config/{APP_NAME_CAP}/config/config.py) # Settings
|
||||
# Dashboard
|
||||
bind = {bind_vars.get("prefix_dashboard", "SUPER")}, {bind_vars.get("suffix_dashboard", "G")}, exec, $fabricSend "dashboard.toggle_dashboard()"
|
||||
# Restart Modus
|
||||
bind = {bind_vars.get("prefix_restart_inspector", "SUPER CTRL ALT")}, {bind_vars.get("suffix_restart_inspector", "B")}, exec, killall {APP_NAME}; uwsm-app $(GTK_DEBUG=interactive python {home}/.config/{APP_NAME_CAP}/main.py) # Restart with inspector
|
||||
|
||||
|
||||
@@ -69,12 +69,8 @@ tooltip > * {
|
||||
box-shadow: 0 0 3px alpha(black, 0.7);
|
||||
}
|
||||
|
||||
#dashboard.hide {
|
||||
margin: -999px;
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
#dashboard.reveal {
|
||||
margin: 0px;
|
||||
|
||||
#dashboard-window {
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
#dashboard {
|
||||
@@ -154,26 +150,4 @@ tooltip > * {
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
#notification-source {
|
||||
color: var(--outline);
|
||||
}
|
||||
|
||||
#notificationss-icon {
|
||||
font-size: 36px;
|
||||
margin-right: 27px;
|
||||
margin-left: 7px;
|
||||
color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#notification-container {
|
||||
background-color: var(--surface);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
#notification-box {
|
||||
background-color: black;
|
||||
border-radius: 25px;
|
||||
padding: 10px;
|
||||
min-width: 364px; /* 290+74 */
|
||||
margin-top: 3px;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ from modules.launcher import Launcher
|
||||
from modules.notification_popup import NotificationPopup
|
||||
from modules.osd import OSD
|
||||
from modules.switcher import ApplicationSwitcher
|
||||
from modules.dashboard.main import DashboardWindow
|
||||
from modules.dashboard import DashboardWindow
|
||||
|
||||
|
||||
for log in [
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
Dashboard module for Modus.
|
||||
Provides a dashboard interface with tiles and notifications.
|
||||
"""
|
||||
|
||||
from .main import DashboardWindow
|
||||
|
||||
__all__ = ["DashboardWindow"]
|
||||
+415
-94
@@ -1,19 +1,384 @@
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.label import Label
|
||||
from fabric.widgets.centerbox import CenterBox
|
||||
from fabric.widgets.button import Button
|
||||
from fabric.widgets.revealer import Revealer
|
||||
from fabric.widgets.scrolledwindow import ScrolledWindow
|
||||
from fabric.widgets.centerbox import CenterBox
|
||||
from fabric.core.service import Property
|
||||
from gi.repository import GLib, Gtk
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from modules.dashboard.bluetooth import Bluetooth
|
||||
from modules.dashboard.network import Network
|
||||
from modules.dashboard.tile import Tile, TileSpecial
|
||||
from utils.wavy_clock import WavyCircle
|
||||
from modules.dashboard.tile import TileSpecial
|
||||
from modules.dashboard.player_mini import PlayerContainerMini
|
||||
from utils.notification_utils import (
|
||||
get_shared_notification_history,
|
||||
PERSISTENT_HISTORY_FILE,
|
||||
create_historical_notification_from_data,
|
||||
compute_time_label,
|
||||
)
|
||||
|
||||
from utils.wayland import WaylandWindow as Window
|
||||
|
||||
import utils.icons as icons
|
||||
import config.info as info
|
||||
|
||||
|
||||
class DashboardNotificationItem(Box):
|
||||
"""Individual notification item for dashboard"""
|
||||
|
||||
def __init__(self, notification_data, **kwargs):
|
||||
super().__init__(
|
||||
name="notification-container",
|
||||
orientation="v",
|
||||
h_align="fill",
|
||||
h_expand=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
self.notification_data = notification_data
|
||||
|
||||
# Create historical notification from data
|
||||
hist_notif = create_historical_notification_from_data(notification_data)
|
||||
|
||||
# Create timestamp
|
||||
try:
|
||||
arrival_time = datetime.fromisoformat(hist_notif.timestamp)
|
||||
except Exception:
|
||||
arrival_time = datetime.now()
|
||||
|
||||
# Create time label
|
||||
self.time_label = Label(
|
||||
name="notification-timestamp",
|
||||
markup=compute_time_label(arrival_time),
|
||||
h_align="start",
|
||||
ellipsization="end",
|
||||
)
|
||||
|
||||
# Create notification image box
|
||||
# For dashboard, we'll use a simple icon instead of trying to load cached images
|
||||
self.notif_image_box = Box(
|
||||
name="notification-image",
|
||||
orientation="v",
|
||||
children=[
|
||||
Label(name="notification-icon", markup=icons.notifications),
|
||||
Box(v_expand=True),
|
||||
],
|
||||
)
|
||||
|
||||
# Create summary label
|
||||
self.notif_summary_label = Label(
|
||||
name="notification-summary",
|
||||
markup=hist_notif.summary,
|
||||
h_align="start",
|
||||
ellipsization="end",
|
||||
)
|
||||
|
||||
# Create app name label
|
||||
self.notif_app_name_label = Label(
|
||||
name="notification-app-name",
|
||||
markup=f"{hist_notif.app_name}",
|
||||
h_align="start",
|
||||
ellipsization="end",
|
||||
)
|
||||
|
||||
# Create body label
|
||||
self.notif_body_label = (
|
||||
Label(
|
||||
name="notification-body",
|
||||
markup=hist_notif.body,
|
||||
h_align="start",
|
||||
ellipsization="end",
|
||||
line_wrap="word-char",
|
||||
)
|
||||
if hist_notif.body
|
||||
else Box()
|
||||
)
|
||||
if hist_notif.body:
|
||||
self.notif_body_label.set_single_line_mode(True)
|
||||
|
||||
# Create summary box with separators
|
||||
self.notif_summary_box = Box(
|
||||
name="notification-summary-box",
|
||||
orientation="h",
|
||||
children=[
|
||||
self.notif_summary_label,
|
||||
Box(
|
||||
name="notif-sep",
|
||||
h_expand=False,
|
||||
v_expand=False,
|
||||
h_align="center",
|
||||
v_align="center",
|
||||
),
|
||||
self.notif_app_name_label,
|
||||
Box(
|
||||
name="notif-sep",
|
||||
h_expand=False,
|
||||
v_expand=False,
|
||||
h_align="center",
|
||||
v_align="center",
|
||||
),
|
||||
self.time_label,
|
||||
],
|
||||
)
|
||||
|
||||
# Create text box
|
||||
self.notif_text_box = Box(
|
||||
name="notification-text",
|
||||
orientation="v",
|
||||
v_align="center",
|
||||
h_expand=True,
|
||||
children=[
|
||||
self.notif_summary_box,
|
||||
self.notif_body_label,
|
||||
],
|
||||
)
|
||||
|
||||
# Create close button
|
||||
self.notif_close_button = Button(
|
||||
name="notif-close-button",
|
||||
child=Label(name="notif-close-label", markup=icons.cancel),
|
||||
on_clicked=lambda *_: self.remove_notification(),
|
||||
)
|
||||
|
||||
self.notif_close_button_box = Box(
|
||||
orientation="v",
|
||||
children=[
|
||||
self.notif_close_button,
|
||||
Box(v_expand=True),
|
||||
],
|
||||
)
|
||||
|
||||
# Create main content box
|
||||
content_box = Box(
|
||||
name="notification-box-hist",
|
||||
spacing=8,
|
||||
children=[
|
||||
self.notif_image_box,
|
||||
self.notif_text_box,
|
||||
self.notif_close_button_box,
|
||||
],
|
||||
)
|
||||
|
||||
self.add(content_box)
|
||||
|
||||
def remove_notification(self):
|
||||
"""Remove this notification from the dashboard"""
|
||||
if self.get_parent():
|
||||
self.get_parent().remove(self)
|
||||
self.destroy()
|
||||
|
||||
|
||||
class DashboardNotifications(Box):
|
||||
"""Dashboard notifications container that shows real notifications"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(
|
||||
name="notification-history",
|
||||
orientation="v",
|
||||
**kwargs
|
||||
)
|
||||
|
||||
self.notification_items = []
|
||||
self.max_notifications = 5 # Limit to 5 notifications in dashboard
|
||||
|
||||
# Create header components (matching dock notifications)
|
||||
self.header_label = Label(
|
||||
name="nhh",
|
||||
label="Notifications",
|
||||
h_align="start",
|
||||
h_expand=True,
|
||||
)
|
||||
self.header_switch = Gtk.Switch(name="dnd-switch")
|
||||
self.header_switch.set_vexpand(False)
|
||||
self.header_switch.set_valign(Gtk.Align.CENTER)
|
||||
self.header_switch.set_active(False)
|
||||
self.header_clean = Button(
|
||||
name="nhh-button",
|
||||
child=Label(name="nhh-button-label", markup=icons.trash),
|
||||
on_clicked=self.clear_history,
|
||||
)
|
||||
self.do_not_disturb_enabled = False
|
||||
self.header_switch.connect("notify::active", self.on_do_not_disturb_changed)
|
||||
self.dnd_label = Label(name="dnd-label", markup=icons.notifications_off)
|
||||
|
||||
self.history_header = CenterBox(
|
||||
name="notification-history-header",
|
||||
spacing=8,
|
||||
start_children=[self.header_switch, self.dnd_label],
|
||||
center_children=[self.header_label],
|
||||
end_children=[self.header_clean],
|
||||
)
|
||||
|
||||
# Create notifications list
|
||||
self.notifications_list = Box(
|
||||
name="notifications-list",
|
||||
orientation="v",
|
||||
spacing=4,
|
||||
h_expand=True,
|
||||
v_expand=True,
|
||||
h_align="fill",
|
||||
v_align="fill",
|
||||
)
|
||||
|
||||
# Create "no notifications" label
|
||||
self.no_notifications_label = Label(
|
||||
name="no-notif",
|
||||
markup=icons.notifications_clear,
|
||||
v_align="fill",
|
||||
h_align="fill",
|
||||
v_expand=True,
|
||||
h_expand=True,
|
||||
justification="center",
|
||||
)
|
||||
self.no_notifications_box = Box(
|
||||
name="no-notifications-box",
|
||||
v_align="fill",
|
||||
h_align="fill",
|
||||
v_expand=True,
|
||||
h_expand=True,
|
||||
children=[self.no_notifications_label],
|
||||
)
|
||||
|
||||
# Add components to main container
|
||||
self.add(self.history_header)
|
||||
self.add(self.notifications_list)
|
||||
|
||||
# Add the no notifications box initially to the notifications list
|
||||
self.notifications_list.add(self.no_notifications_box)
|
||||
|
||||
# Connect to shared notification history
|
||||
self._connect_to_notifications()
|
||||
|
||||
# Load and sync DND state
|
||||
self._load_and_sync_dnd_state()
|
||||
|
||||
# Load initial notifications
|
||||
self._load_recent_notifications()
|
||||
|
||||
def _connect_to_notifications(self):
|
||||
"""Connect to the shared notification history for real-time updates"""
|
||||
try:
|
||||
self.shared_history = get_shared_notification_history()
|
||||
self.shared_history.connect("notification-added", self._on_notification_added)
|
||||
self.shared_history.connect("dnd-state-changed", self._on_dnd_state_changed)
|
||||
except Exception as e:
|
||||
print(f"Could not connect to notification history: {e}")
|
||||
|
||||
def _on_notification_added(self, shared_history):
|
||||
"""Handle new notification added"""
|
||||
GLib.idle_add(self._refresh_notifications)
|
||||
|
||||
def _on_dnd_state_changed(self, notification_history, dnd_enabled):
|
||||
"""Handle DND state change"""
|
||||
self.do_not_disturb_enabled = dnd_enabled
|
||||
self.header_switch.set_active(dnd_enabled)
|
||||
|
||||
def _load_and_sync_dnd_state(self):
|
||||
"""Load and sync DND state from shared history"""
|
||||
try:
|
||||
if hasattr(self, 'shared_history'):
|
||||
dnd_enabled = self.shared_history.do_not_disturb_enabled
|
||||
self.header_switch.set_active(dnd_enabled)
|
||||
self.do_not_disturb_enabled = dnd_enabled
|
||||
except Exception as e:
|
||||
print(f"Could not sync DND state: {e}")
|
||||
|
||||
def on_do_not_disturb_changed(self, switch, pspec):
|
||||
"""Handle DND switch toggle"""
|
||||
self.do_not_disturb_enabled = switch.get_active()
|
||||
|
||||
try:
|
||||
if hasattr(self, 'shared_history'):
|
||||
self.shared_history.set_do_not_disturb_enabled(self.do_not_disturb_enabled)
|
||||
except Exception as e:
|
||||
print(f"Could not update shared DND state: {e}")
|
||||
|
||||
def clear_history(self, *args):
|
||||
"""Clear all notifications"""
|
||||
# Clear notification items
|
||||
for item in self.notification_items[:]:
|
||||
self.notifications_list.remove(item)
|
||||
item.destroy()
|
||||
self.notification_items.clear()
|
||||
|
||||
# Clear persistent history
|
||||
try:
|
||||
if hasattr(self, 'shared_history'):
|
||||
self.shared_history.clear_history()
|
||||
except Exception as e:
|
||||
print(f"Could not clear shared history: {e}")
|
||||
|
||||
# Update visibility
|
||||
self._update_no_notifications_visibility()
|
||||
|
||||
def _load_recent_notifications(self):
|
||||
"""Load recent notifications from persistent storage"""
|
||||
try:
|
||||
if os.path.exists(PERSISTENT_HISTORY_FILE):
|
||||
with open(PERSISTENT_HISTORY_FILE, "r") as f:
|
||||
notifications = json.load(f)
|
||||
|
||||
# Get the most recent notifications (up to max_notifications)
|
||||
recent_notifications = notifications[-self.max_notifications:]
|
||||
|
||||
for notif_data in reversed(recent_notifications):
|
||||
self._add_notification_item(notif_data)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error loading recent notifications: {e}")
|
||||
|
||||
def _refresh_notifications(self):
|
||||
"""Refresh the notification list"""
|
||||
# Clear existing notifications
|
||||
for item in self.notification_items[:]:
|
||||
self.notifications_list.remove(item)
|
||||
item.destroy()
|
||||
self.notification_items.clear()
|
||||
|
||||
# Reload recent notifications
|
||||
self._load_recent_notifications()
|
||||
|
||||
# Update visibility
|
||||
self._update_no_notifications_visibility()
|
||||
|
||||
def _add_notification_item(self, notification_data):
|
||||
"""Add a notification item to the dashboard"""
|
||||
# Remove no notifications box if it's showing
|
||||
if self.no_notifications_box in self.notifications_list.get_children():
|
||||
self.notifications_list.remove(self.no_notifications_box)
|
||||
|
||||
if len(self.notification_items) >= self.max_notifications:
|
||||
# Remove oldest notification
|
||||
oldest = self.notification_items.pop(0)
|
||||
self.notifications_list.remove(oldest)
|
||||
oldest.destroy()
|
||||
|
||||
# Create new notification item
|
||||
item = DashboardNotificationItem(notification_data)
|
||||
self.notification_items.append(item)
|
||||
self.notifications_list.add(item)
|
||||
|
||||
# Update visibility
|
||||
self._update_no_notifications_visibility()
|
||||
|
||||
# Show all to ensure visibility
|
||||
self.show_all()
|
||||
|
||||
def _update_no_notifications_visibility(self):
|
||||
"""Update visibility of no notifications label"""
|
||||
has_notifications = bool(self.notification_items)
|
||||
|
||||
if has_notifications:
|
||||
# Hide no notifications box
|
||||
if self.no_notifications_box in self.notifications_list.get_children():
|
||||
self.notifications_list.remove(self.no_notifications_box)
|
||||
else:
|
||||
# Show no notifications box
|
||||
if self.no_notifications_box not in self.notifications_list.get_children():
|
||||
self.notifications_list.add(self.no_notifications_box)
|
||||
|
||||
|
||||
class Dashboard(Box):
|
||||
@@ -33,43 +398,23 @@ class Dashboard(Box):
|
||||
props=self.mini_player, mini_props=self.mini_player.get_mini_view()
|
||||
)
|
||||
|
||||
# self.controls = controls
|
||||
# self.brightness_revealer_mui = self.controls.get_brightness_slider_mui()
|
||||
#
|
||||
self.wavy = self.gtk_wrapper = CenterBox(
|
||||
orientation="v",
|
||||
# Create real notifications component
|
||||
self.dashboard_notifications = DashboardNotifications()
|
||||
|
||||
# Create scrolled window for notifications (matching dock notifications style)
|
||||
self.notifications_scrolled = ScrolledWindow(
|
||||
name="notification-history-scrolled-window",
|
||||
child=self.dashboard_notifications,
|
||||
h_scrollbar_policy="never",
|
||||
v_scrollbar_policy="automatic",
|
||||
min_content_size=(400, 200),
|
||||
max_content_size=(450, 300),
|
||||
h_expand=True,
|
||||
v_expand=True,
|
||||
h_align="fill",
|
||||
v_align="fill",
|
||||
center_children=WavyCircle(),
|
||||
)
|
||||
|
||||
self.low_bat_msg = Label(label="Low Battery fam (<15%)")
|
||||
|
||||
self.content_box = Box(
|
||||
orientation="v",
|
||||
children=[
|
||||
Label(name="notification-source", label="Modus", h_align=True),
|
||||
self.low_bat_msg,
|
||||
],
|
||||
)
|
||||
|
||||
close_btn = Button(
|
||||
name="close-button",
|
||||
child=Label(name="close-label", markup=icons.cancel),
|
||||
tooltip_text="Exit",
|
||||
on_clicked=lambda *_: print("clicked close"),
|
||||
)
|
||||
|
||||
self.notification_box = Box(
|
||||
name="notification-box",
|
||||
style_classes="vertical" if info.VERTICAL else "horizontal",
|
||||
children=[
|
||||
Label(name="notificationss-icon", h_align=True, markup=icons.blur),
|
||||
Box(h_expand=True, children=self.content_box),
|
||||
Box(children=close_btn),
|
||||
],
|
||||
propagate_width=False,
|
||||
propagate_height=False,
|
||||
)
|
||||
|
||||
self.tiles = Box(
|
||||
@@ -79,72 +424,23 @@ class Dashboard(Box):
|
||||
self.mini_player_tile,
|
||||
],
|
||||
)
|
||||
self.low_bat_msg_2 = Label(label="Notification ctl test")
|
||||
|
||||
self.content_box_2 = Box(
|
||||
orientation="v",
|
||||
children=[
|
||||
Label(name="notification-source", label="System", h_align=True),
|
||||
self.low_bat_msg_2,
|
||||
],
|
||||
)
|
||||
|
||||
close_btn_2 = Button(
|
||||
name="close-button",
|
||||
child=Label(name="close-label", markup=icons.cancel),
|
||||
tooltip_text="Exit",
|
||||
on_clicked=lambda *_: print("clicked close"),
|
||||
)
|
||||
|
||||
self.notification_box_2 = Box(
|
||||
name="notification-box",
|
||||
style_classes="vertical" if info.VERTICAL else "horizontal",
|
||||
children=[
|
||||
Label(name="notificationss-icon", h_align=True, markup=icons.blur),
|
||||
Box(h_expand=True, children=self.content_box_2),
|
||||
Box(children=close_btn_2),
|
||||
],
|
||||
)
|
||||
|
||||
self.notification_container = Revealer(
|
||||
transition_duration=250,
|
||||
transition_type="slide-down",
|
||||
style="background-color:blue;",
|
||||
h_expand=True,
|
||||
child=Box(
|
||||
name="notification-history-popup-content",
|
||||
orientation="v",
|
||||
spacing=8,
|
||||
h_expand=True,
|
||||
v_expand=True,
|
||||
children=[
|
||||
Box(
|
||||
name="notification-container",
|
||||
orientation="v",
|
||||
v_expand=True,
|
||||
style="padding:3px; padding-top:0px",
|
||||
children=[self.notification_box, self.notification_box_2],
|
||||
),
|
||||
Box(
|
||||
v_expand=True,
|
||||
h_expand=True,
|
||||
children=self.wavy,
|
||||
),
|
||||
],
|
||||
children=[self.notifications_scrolled],
|
||||
style_classes=["notification-history-popup"],
|
||||
),
|
||||
child_revealed=True,
|
||||
)
|
||||
self.children = [
|
||||
# Box(
|
||||
# name="inner",
|
||||
# orientation="h",
|
||||
# children=[
|
||||
# CenterBox(
|
||||
# style_classes="scale-icon-container",
|
||||
# center_children=Label(
|
||||
# style_classes="scale-icon", markup=icons.brightness
|
||||
# ),
|
||||
# ),
|
||||
# self.brightness_revealer_mui,
|
||||
# ],
|
||||
# ),
|
||||
Box(name="inner", children=self.tiles),
|
||||
Box(
|
||||
children=[
|
||||
@@ -174,13 +470,38 @@ class Dashboard(Box):
|
||||
|
||||
|
||||
class DashboardWindow(Window):
|
||||
|
||||
visible = Property(bool, flags="read-write", default_value=False)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(
|
||||
name="dashboard-window",
|
||||
layer="top",
|
||||
anchor="bottom",
|
||||
exclusivity="none",
|
||||
keyboard_mode="on-demand",
|
||||
child=Dashboard(),
|
||||
visible=True,
|
||||
all_visible=True,
|
||||
visible=False,
|
||||
all_visible=False,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# self.hide()
|
||||
# Add escape key binding to close dashboard
|
||||
self.add_keybinding("Escape", lambda *_: self.close_dashboard())
|
||||
self.hide()
|
||||
|
||||
|
||||
def show_dashboard(self):
|
||||
self.show_all()
|
||||
self.visible = True
|
||||
|
||||
def close_dashboard(self):
|
||||
self.hide()
|
||||
self.visible = False
|
||||
|
||||
def toggle_dashboard(self):
|
||||
if self.visible:
|
||||
self.close_dashboard()
|
||||
else:
|
||||
self.show_dashboard()
|
||||
|
||||
|
||||
+3
-3
@@ -157,9 +157,9 @@
|
||||
inset 60px 0px 10px rgba(255, 255, 255, 1); */
|
||||
|
||||
box-shadow:
|
||||
inset 0 0 100px rgba(148, 148, 148, 0.2),
|
||||
inset 70px 0 20px rgba(255, 255, 255, 0.2),
|
||||
inset 0px 0px 20px 5px rgba(255, 255, 255, 0.2);
|
||||
inset 0 0 100px rgba(148, 148, 148, 0.3),
|
||||
inset 70px 0 20px rgba(255, 255, 255, 0.3),
|
||||
inset 0px 0px 20px 5px rgba(255, 255, 255, 0.3);
|
||||
border-top-right-radius: 15px;
|
||||
border-bottom-right-radius: 15px;
|
||||
border-top-left-radius: 20px;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to send sample notifications for testing the dashboard notification display.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
|
||||
def send_test_notification(app_name, title, body, icon=None):
|
||||
"""Send a test notification using notify-send"""
|
||||
cmd = ["notify-send", "-a", app_name, title, body]
|
||||
if icon:
|
||||
cmd.extend(["-i", icon])
|
||||
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
print(f"Sent notification: {app_name} - {title}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to send notification: {e}")
|
||||
|
||||
def main():
|
||||
"""Send a series of test notifications"""
|
||||
print("Sending test notifications for dashboard...")
|
||||
|
||||
# Test notifications with different apps and content
|
||||
test_notifications = [
|
||||
("Modus", "Dashboard Test", "This is a test notification for the dashboard"),
|
||||
("System", "Low Battery", "Battery level is below 15%"),
|
||||
("Firefox", "Download Complete", "Your file has been downloaded successfully"),
|
||||
("Spotify", "Now Playing", "♪ Your favorite song is now playing"),
|
||||
("Telegram", "New Message", "You have received a new message"),
|
||||
]
|
||||
|
||||
for i, (app, title, body) in enumerate(test_notifications):
|
||||
send_test_notification(app, title, body)
|
||||
if i < len(test_notifications) - 1: # Don't sleep after the last notification
|
||||
time.sleep(2) # Wait 2 seconds between notifications
|
||||
|
||||
print("\nTest notifications sent!")
|
||||
print("Open the dashboard (SUPER+G) to see the notifications.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user