[geary/wip/774442-in-app-notifications] Implement in-app notifications. Bug 774442.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/774442-in-app-notifications] Implement in-app notifications. Bug 774442.
- Date: Mon, 23 Oct 2017 10:40:49 +0000 (UTC)
commit 0f8f98d8878215f4a28d2eb80213c9337e804211
Author: Niels De Graef <nielsdegraef gmail com>
Date: Sat May 27 14:29:45 2017 +0200
Implement in-app notifications. Bug 774442.
Implemented it for the mail sent-notification.
Signed-off-by: Niels De Graef <nielsdegraef gmail com>
po/POTFILES.in | 2 +
src/CMakeLists.txt | 1 +
src/client/application/geary-controller.vala | 3 +
src/client/components/main-window.vala | 7 +
src/client/notification/in-app-notification.vala | 66 +++++++++++
src/engine/rfc822/rfc822-mailbox-addresses.vala | 20 +++
ui/CMakeLists.txt | 1 +
ui/in-app-notification.ui | 48 ++++++++
ui/main-window.ui | 135 +++++++++++-----------
9 files changed, 218 insertions(+), 65 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dea321b..88f4a8e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -69,6 +69,7 @@ src/client/folder-list/folder-list-inboxes-branch.vala
src/client/folder-list/folder-list-search-branch.vala
src/client/folder-list/folder-list-special-grouping.vala
src/client/folder-list/folder-list-tree.vala
+src/client/notification/in-app-notification.vala
src/client/notification/libmessagingmenu.vala
src/client/notification/libnotify.vala
src/client/notification/new-messages-indicator.vala
@@ -404,6 +405,7 @@ src/mailer/main.vala
[type: gettext/glade]ui/folder-popover.ui
[type: gettext/glade]ui/gtk/help-overlay.ui
[type: gettext/glade]ui/gtk/menus.ui
+[type: gettext/glade]ui/in-app-notification.ui
[type: gettext/glade]ui/login.glade
[type: gettext/glade]ui/main-toolbar.ui
[type: gettext/glade]ui/main-toolbar-menus.ui
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bb56e06..59043d9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -388,6 +388,7 @@ client/folder-list/folder-list-inbox-folder-entry.vala
client/folder-list/folder-list-search-branch.vala
client/folder-list/folder-list-special-grouping.vala
+client/notification/in-app-notification.vala
client/notification/libmessagingmenu.vala
client/notification/libnotify.vala
client/notification/new-messages-indicator.vala
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 040dede..ae37bb7 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -2541,6 +2541,9 @@ public class GearyController : Geary.BaseObject {
}
private void on_sent(Geary.RFC822.Message rfc822) {
+ string message = _("Successfully sent mail to %s.".printf(rfc822.to.to_short_string()));
+ InAppNotification notification = new InAppNotification(message);
+ this.main_window.add_notification(notification);
Libnotify.play_sound("message-sent-email");
}
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 13fedf7..d9ac413 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -49,6 +49,8 @@ public class MainWindow : Gtk.ApplicationWindow {
private Gtk.Box conversation_box;
[GtkChild]
private Gtk.ScrolledWindow conversation_list_scrolled;
+ [GtkChild]
+ private Gtk.Overlay overlay;
/** Fired when the shift key is pressed or released. */
@@ -139,6 +141,11 @@ public class MainWindow : Gtk.ApplicationWindow {
}
}
+ public void add_notification(InAppNotification notification) {
+ this.overlay.add_overlay(notification);
+ notification.show();
+ }
+
private void set_styling() {
Gtk.CssProvider provider = new Gtk.CssProvider();
Gtk.StyleContext.add_provider_for_screen(Gdk.Display.get_default().get_default_screen(),
diff --git a/src/client/notification/in-app-notification.vala
b/src/client/notification/in-app-notification.vala
new file mode 100644
index 0000000..bc2b6e4
--- /dev/null
+++ b/src/client/notification/in-app-notification.vala
@@ -0,0 +1,66 @@
+/* Copyright 2017 Software Freedom Conservancy Inc.
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * Represents an in-app notification.
+ *
+ * Following the GNOME HIG, it should only contain a label and maybe a button.
+ */
+[GtkTemplate (ui = "/org/gnome/Geary/in-app-notification.ui")]
+public class InAppNotification : Gtk.Revealer {
+
+ /** Close the in-app notification after 3 seconds by default. */
+ public const uint DEFAULT_KEEPALIVE = 3;
+
+ [GtkChild]
+ private Gtk.Label message_label;
+ [GtkChild]
+ private Gtk.Button action_button;
+
+ /**
+ * Creates an in-app notification.
+ *
+ * @param message The messag that should be displayed.
+ * @param keepalive The amount of seconds that the notification should stay visible.
+ */
+ public InAppNotification(string message, uint keepalive = DEFAULT_KEEPALIVE) {
+ this.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
+ this.message_label.label = message;
+
+ // Close after the given amount of time.
+ Timeout.add_seconds(keepalive, () => { close(); return false; });
+ }
+
+ /**
+ * Sets a button for the notification.
+ */
+ public void set_button(string label, string action_name) {
+ this.action_button.visible = true;
+ this.action_button.label = label;
+ this.action_button.action_name = action_name;
+ }
+
+ public override void show() {
+ base.show();
+ this.reveal_child = true;
+ }
+
+ /**
+ * Closes the in-app notification.
+ */
+ [GtkCallback]
+ public void close() {
+ // Allows for the disappearing transition
+ this.reveal_child = false;
+ }
+
+ // Make sure the notification gets destroyed after closing.
+ [GtkCallback]
+ private void on_child_revealed(Object src, ParamSpec p) {
+ if (!this.child_revealed)
+ destroy();
+ }
+}
diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala
index b5f39b1..379aec5 100644
--- a/src/engine/rfc822/rfc822-mailbox-addresses.vala
+++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala
@@ -124,5 +124,25 @@ public class Geary.RFC822.MailboxAddresses : Geary.MessageData.AbstractMessageDa
public override string to_string() {
return MailboxAddress.list_to_string(addrs, "(no addresses)", (a) => a.to_string());
}
+
+ /**
+ * Returns a human-readable short string.
+ * Useful in case there are a lot of recipients, or there is little room for the display.
+ */
+ public string to_short_string() {
+ if (this.size == 0)
+ return _("(No recipients)");
+
+ // Always mention the first recipient
+ string first_recipient = this.get(0).get_short_address();
+ if (this.size == 1)
+ return first_recipient;
+
+ // If more than one, add the amount of participants
+ if (this.size == 2)
+ return _("%s and 1 other recipient").printf(first_recipient);
+
+ return _("%s and %d others").printf(first_recipient, this.size - 1);
+ }
}
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index 05a74e7..5426c65 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -26,6 +26,7 @@ set(RESOURCE_LIST
STRIPBLANKS "folder-popover.ui"
STRIPBLANKS "gtk/help-overlay.ui"
STRIPBLANKS "gtk/menus.ui"
+ STRIPBLANKS "in-app-notification.ui"
STRIPBLANKS "login.glade"
STRIPBLANKS "main-toolbar.ui"
STRIPBLANKS "main-toolbar-menus.ui"
diff --git a/ui/in-app-notification.ui b/ui/in-app-notification.ui
new file mode 100644
index 0000000..087d794
--- /dev/null
+++ b/ui/in-app-notification.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.14"/>
+ <template class="InAppNotification" parent="GtkRevealer">
+ <property name="visible">False</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <signal name="notify::child-revealed" handler="on_child_revealed" swapped="no"/>
+ <child>
+ <object class="GtkBox" id="layout">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">6</property>
+ <style>
+ <class name="app-notification"/>
+ </style>
+ <child>
+ <object class="GtkLabel" id="message_label">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="action_button">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <signal name="clicked" handler="close" swapped="no"/>
+ <style>
+ <class name="flat"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">window-close-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/ui/main-window.ui b/ui/main-window.ui
index 1ed5894..eac0386 100644
--- a/ui/main-window.ui
+++ b/ui/main-window.ui
@@ -10,122 +10,127 @@
<signal name="key_release_event" handler="on_key_release_event"/>
<signal name="focus_in_event" handler="on_focus_event"/>
<child>
- <object class="GtkBox" id="main_layout">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">0</property>
+ <object class="GtkOverlay" id="overlay">
+ <property name="visible">False</property>
<child>
- <object class="GtkPaned" id="conversations_paned">
+ <object class="GtkBox" id="main_layout">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">0</property>
<child>
- <object class="GtkBox" id="search_bar_box">
+ <object class="GtkPaned" id="conversations_paned">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">0</property>
- <style>
- <class name="sidebar"/>
- </style>
+ <property name="orientation">horizontal</property>
<child>
- <object class="GtkPaned" id="folder_paned">
+ <object class="GtkBox" id="search_bar_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">0</property>
<style>
- <class name="geary-sidebar-pane-separator"/>
+ <class name="sidebar"/>
</style>
<child>
- <object class="GtkBox" id="folder_box">
+ <object class="GtkPaned" id="folder_paned">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">0</property>
+ <property name="orientation">horizontal</property>
+ <style>
+ <class name="geary-sidebar-pane-separator"/>
+ </style>
<child>
- <object class="GtkFrame" id="folder_frame">
+ <object class="GtkBox" id="folder_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="shadow_type">in</property>
- <style>
- <class name="geary-folder-frame"/>
- </style>
+ <property name="orientation">vertical</property>
+ <property name="spacing">0</property>
<child>
- <object class="GtkScrolledWindow" id="folder_list_scrolled">
+ <object class="GtkFrame" id="folder_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="width_request">100</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <style>
+ <class name="geary-folder-frame"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow" id="folder_list_scrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_request">100</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
</child>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="resize">False</property>
+ <property name="shrink">False</property>
</packing>
</child>
- </object>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">False</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="conversation_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">0</property>
<child>
- <object class="GtkFrame" id="conversation_frame">
+ <object class="GtkBox" id="conversation_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="shadow_type">in</property>
- <style>
- <class name="geary-conversation-frame"/>
- </style>
+ <property name="orientation">vertical</property>
+ <property name="spacing">0</property>
<child>
- <object class="GtkScrolledWindow" id="conversation_list_scrolled">
+ <object class="GtkFrame" id="conversation_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="width_request">250</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <style>
+ <class name="geary-conversation-frame"/>
+ </style>
+ <child>
+ <object class="GtkScrolledWindow" id="conversation_list_scrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_request">250</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
</child>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="resize">True</property>
+ <property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
- <property name="resize">True</property>
- <property name="shrink">False</property>
+ <property name="pack_type">end</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
</object>
<packing>
- <property name="pack_type">end</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="resize">False</property>
+ <property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
- <property name="resize">False</property>
- <property name="shrink">False</property>
+ <property name="pack_type">end</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
</object>
- <packing>
- <property name="pack_type">end</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
</child>
</object>
</child>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]