Add support for getting at the actions of notifications inline.
This commit is contained in:
@@ -421,8 +421,7 @@ class NotificationListGUI:
|
||||
"""The dialog containing the notifications list."""
|
||||
|
||||
RESPONSE_COPY = 1
|
||||
RESPONSE_ACTIONS = 2
|
||||
RESPONSE_DISMISS = 3
|
||||
RESPONSE_DISMISS = 2
|
||||
|
||||
def __init__(self, presenter, script, title, column_headers, entries):
|
||||
self._presenter = presenter
|
||||
@@ -431,17 +430,14 @@ class NotificationListGUI:
|
||||
self._tree = None
|
||||
self._selection = None
|
||||
self._dismiss_button = None
|
||||
self._actions_button = None
|
||||
self._actions_box = None
|
||||
self._actions_status_label = None
|
||||
self._gui = self._create_dialog(title, column_headers, entries)
|
||||
|
||||
def _create_dialog(self, title, column_headers, entries):
|
||||
dialog = Gtk.Dialog(title, None, Gtk.DialogFlags.MODAL)
|
||||
dialog.set_default_size(600, 400)
|
||||
dialog.add_button(Gtk.STOCK_COPY, self.RESPONSE_COPY)
|
||||
self._actions_button = dialog.add_button(
|
||||
guilabels.NOTIFICATIONS_ACTIONS_BUTTON,
|
||||
self.RESPONSE_ACTIONS,
|
||||
)
|
||||
self._dismiss_button = dialog.add_button(
|
||||
guilabels.NOTIFICATIONS_DISMISS_BUTTON,
|
||||
self.RESPONSE_DISMISS,
|
||||
@@ -451,10 +447,13 @@ class NotificationListGUI:
|
||||
dialog.set_default_response(Gtk.ResponseType.CLOSE)
|
||||
|
||||
grid = Gtk.Grid()
|
||||
grid.set_row_spacing(12)
|
||||
content_area = dialog.get_content_area()
|
||||
content_area.add(grid)
|
||||
|
||||
scrolled_window = Gtk.ScrolledWindow()
|
||||
scrolled_window.set_hexpand(True)
|
||||
scrolled_window.set_vexpand(True)
|
||||
grid.add(scrolled_window)
|
||||
|
||||
tree = Gtk.TreeView()
|
||||
@@ -492,6 +491,29 @@ class NotificationListGUI:
|
||||
selection.select_path(0)
|
||||
self._selection = selection
|
||||
self._tree = tree
|
||||
|
||||
actions_frame = Gtk.Frame(label=guilabels.NOTIFICATIONS_ACTIONS_TITLE)
|
||||
actions_frame.set_label_align(0.0, 0.5)
|
||||
actions_accessible = actions_frame.get_accessible()
|
||||
if actions_accessible:
|
||||
actions_accessible.set_name(guilabels.NOTIFICATIONS_ACTIONS_TITLE)
|
||||
grid.attach_next_to(actions_frame, scrolled_window, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
|
||||
actions_content = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
actions_content.set_margin_top(6)
|
||||
actions_content.set_margin_bottom(6)
|
||||
actions_content.set_margin_start(6)
|
||||
actions_content.set_margin_end(6)
|
||||
actions_frame.add(actions_content)
|
||||
|
||||
self._actions_status_label = Gtk.Label(xalign=0)
|
||||
self._actions_status_label.set_line_wrap(True)
|
||||
self._actions_status_label.set_no_show_all(True)
|
||||
actions_content.pack_start(self._actions_status_label, False, False, 0)
|
||||
|
||||
self._actions_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
actions_content.pack_start(self._actions_box, False, False, 0)
|
||||
|
||||
dialog.connect("response", self.on_response)
|
||||
dialog.connect("destroy", self._on_destroy)
|
||||
self._update_action_buttons()
|
||||
@@ -508,10 +530,6 @@ class NotificationListGUI:
|
||||
self._copy_selected_notification()
|
||||
return
|
||||
|
||||
if response == self.RESPONSE_ACTIONS:
|
||||
self._show_selected_actions()
|
||||
return
|
||||
|
||||
if response == self.RESPONSE_DISMISS:
|
||||
self._dismiss_selected_notification()
|
||||
return
|
||||
@@ -560,12 +578,70 @@ class NotificationListGUI:
|
||||
def _update_action_buttons(self) -> None:
|
||||
entry = self._get_selected_entry()
|
||||
can_control = self._presenter.can_control_entry(entry)
|
||||
has_actions = bool(self._presenter.get_actions_for_entry(entry))
|
||||
actions = self._presenter.get_actions_for_entry(entry)
|
||||
|
||||
if self._dismiss_button is not None:
|
||||
self._dismiss_button.set_sensitive(can_control)
|
||||
if self._actions_button is not None:
|
||||
self._actions_button.set_sensitive(can_control and has_actions)
|
||||
|
||||
self._clear_inline_action_buttons()
|
||||
|
||||
if not can_control:
|
||||
self._set_inline_action_status(messages.NOTIFICATION_UNAVAILABLE)
|
||||
return
|
||||
|
||||
if not actions:
|
||||
self._set_inline_action_status(messages.NOTIFICATION_NO_ACTIONS)
|
||||
return
|
||||
|
||||
self._set_inline_action_status("")
|
||||
for action_key, label_text in actions.items():
|
||||
self._add_inline_action_button(entry, action_key, label_text)
|
||||
|
||||
def _clear_inline_action_buttons(self) -> None:
|
||||
if self._actions_box is None:
|
||||
return
|
||||
|
||||
for child in self._actions_box.get_children():
|
||||
self._actions_box.remove(child)
|
||||
|
||||
def _set_inline_action_status(self, text: str) -> None:
|
||||
if self._actions_status_label is None:
|
||||
return
|
||||
|
||||
self._actions_status_label.set_text(text)
|
||||
self._actions_status_label.set_visible(bool(text))
|
||||
|
||||
def _add_inline_action_button(
|
||||
self,
|
||||
entry: Optional[NotificationEntry],
|
||||
action_key: str,
|
||||
label_text: str,
|
||||
) -> None:
|
||||
if self._actions_box is None:
|
||||
return
|
||||
|
||||
button = Gtk.Button(label=label_text or action_key)
|
||||
button.connect("clicked", self._on_inline_action_clicked, entry, action_key)
|
||||
self._actions_box.pack_start(button, False, False, 0)
|
||||
self._actions_box.show_all()
|
||||
|
||||
def _on_inline_action_clicked(
|
||||
self,
|
||||
button: Gtk.Button,
|
||||
entry: Optional[NotificationEntry],
|
||||
action_key: str,
|
||||
) -> None:
|
||||
del button
|
||||
self._presenter.refresh_live_notifications()
|
||||
if not self._presenter.can_control_entry(entry):
|
||||
self._script.presentMessage(messages.NOTIFICATION_UNAVAILABLE)
|
||||
self._update_action_buttons()
|
||||
return
|
||||
|
||||
if not self._presenter.invoke_action_for_entry(self._script, entry, action_key):
|
||||
self._script.presentMessage(messages.NOTIFICATION_UNAVAILABLE)
|
||||
|
||||
self._update_action_buttons()
|
||||
|
||||
def _copy_selected_notification(self):
|
||||
entry = self._get_selected_entry()
|
||||
@@ -596,151 +672,6 @@ class NotificationListGUI:
|
||||
|
||||
self._update_action_buttons()
|
||||
|
||||
def _show_selected_actions(self) -> None:
|
||||
self._presenter.refresh_live_notifications()
|
||||
entry = self._get_selected_entry()
|
||||
actions = self._presenter.get_actions_for_entry(entry)
|
||||
if not self._presenter.can_control_entry(entry):
|
||||
self._script.presentMessage(messages.NOTIFICATION_UNAVAILABLE)
|
||||
self._update_action_buttons()
|
||||
return
|
||||
|
||||
if not actions:
|
||||
self._script.presentMessage(messages.NOTIFICATION_NO_ACTIONS)
|
||||
self._update_action_buttons()
|
||||
return
|
||||
|
||||
dialog = NotificationActionsGUI(
|
||||
self._gui,
|
||||
self._script,
|
||||
self._presenter,
|
||||
entry,
|
||||
actions,
|
||||
)
|
||||
dialog.show_gui()
|
||||
|
||||
|
||||
class NotificationActionsGUI:
|
||||
"""Dialog listing live mako actions for a notification."""
|
||||
|
||||
RESPONSE_INVOKE = 1
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: Gtk.Dialog,
|
||||
script: Any,
|
||||
presenter: NotificationPresenter,
|
||||
entry: NotificationEntry,
|
||||
actions: Dict[str, str],
|
||||
) -> None:
|
||||
self._parent = parent
|
||||
self._script = script
|
||||
self._presenter = presenter
|
||||
self._entry = entry
|
||||
self._actions = dict(actions)
|
||||
self._list_box = None
|
||||
self._invoke_button = None
|
||||
self._dialog = self._create_dialog()
|
||||
|
||||
def _create_dialog(self):
|
||||
dialog = Gtk.Dialog(
|
||||
guilabels.NOTIFICATIONS_ACTIONS_TITLE,
|
||||
self._parent,
|
||||
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
)
|
||||
dialog.set_default_size(420, 260)
|
||||
self._invoke_button = dialog.add_button(
|
||||
guilabels.NOTIFICATIONS_INVOKE_ACTION_BUTTON,
|
||||
self.RESPONSE_INVOKE,
|
||||
)
|
||||
dialog.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
|
||||
|
||||
content_area = dialog.get_content_area()
|
||||
scrolled_window = Gtk.ScrolledWindow()
|
||||
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
content_area.add(scrolled_window)
|
||||
|
||||
self._list_box = Gtk.ListBox()
|
||||
self._list_box.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
||||
self._list_box.connect("row-activated", self._on_row_activated)
|
||||
self._list_box.connect("selected-rows-changed", self._on_selection_changed)
|
||||
list_accessible = self._list_box.get_accessible()
|
||||
if list_accessible:
|
||||
list_accessible.set_name(guilabels.NOTIFICATIONS_ACTIONS_TITLE)
|
||||
scrolled_window.add(self._list_box)
|
||||
|
||||
for action_key, label_text in self._actions.items():
|
||||
row = Gtk.ListBoxRow()
|
||||
row._action_key = action_key # type: ignore[attr-defined]
|
||||
label = Gtk.Label(label=label_text or action_key, xalign=0)
|
||||
label.set_margin_start(10)
|
||||
label.set_margin_end(10)
|
||||
label.set_margin_top(6)
|
||||
label.set_margin_bottom(6)
|
||||
row.add(label)
|
||||
self._list_box.add(row)
|
||||
|
||||
first_row = self._list_box.get_row_at_index(0)
|
||||
if first_row is not None:
|
||||
self._list_box.select_row(first_row)
|
||||
|
||||
dialog.connect("response", self._on_response)
|
||||
self._update_invoke_button()
|
||||
return dialog
|
||||
|
||||
def show_gui(self) -> None:
|
||||
self._dialog.show_all()
|
||||
time_stamp = Gtk.get_current_event_time()
|
||||
if not time_stamp or time_stamp > 0xFFFFFFFF:
|
||||
time_stamp = Gdk.CURRENT_TIME
|
||||
self._dialog.present_with_time(int(time_stamp))
|
||||
|
||||
def _on_response(self, dialog, response) -> None:
|
||||
if response == Gtk.ResponseType.CLOSE:
|
||||
self._dialog.destroy()
|
||||
return
|
||||
|
||||
if response == self.RESPONSE_INVOKE:
|
||||
self._invoke_selected_action()
|
||||
|
||||
def _on_row_activated(self, list_box, row) -> None:
|
||||
self._invoke_selected_action()
|
||||
|
||||
def _on_selection_changed(self, list_box) -> None:
|
||||
self._update_invoke_button()
|
||||
|
||||
def _get_selected_action_key(self) -> Optional[str]:
|
||||
if self._list_box is None:
|
||||
return None
|
||||
|
||||
row = self._list_box.get_selected_row()
|
||||
if row is None:
|
||||
return None
|
||||
|
||||
return getattr(row, "_action_key", None)
|
||||
|
||||
def _update_invoke_button(self) -> None:
|
||||
if self._invoke_button is None:
|
||||
return
|
||||
|
||||
self._invoke_button.set_sensitive(self._get_selected_action_key() is not None)
|
||||
|
||||
def _invoke_selected_action(self) -> None:
|
||||
self._presenter.refresh_live_notifications()
|
||||
action_key = self._get_selected_action_key()
|
||||
if not action_key:
|
||||
return
|
||||
|
||||
if not self._presenter.can_control_entry(self._entry):
|
||||
self._script.presentMessage(messages.NOTIFICATION_UNAVAILABLE)
|
||||
self._dialog.destroy()
|
||||
return
|
||||
|
||||
if not self._presenter.invoke_action_for_entry(self._script, self._entry, action_key):
|
||||
self._script.presentMessage(messages.NOTIFICATION_UNAVAILABLE)
|
||||
|
||||
self._dialog.destroy()
|
||||
|
||||
|
||||
_presenter = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user