Push notifications

This commit is contained in:
bleakgrey 2018-05-16 14:23:48 +03:00
parent ae1d615803
commit 44aa22c06e
7 changed files with 99 additions and 16 deletions

View File

@ -10,3 +10,4 @@ Categories=GNOME;GTK;Network;
Keywords=toot;mastodon;social;network;post;
MimeType=text/plain;
StartupNotify=true
X-GNOME-UsesNotifications=true

View File

@ -55,6 +55,23 @@ public enum Tootle.NotificationType {
assert_not_reached();
}
}
public string get_desc_plain (Account? account) {
switch (this) {
case MENTION:
return _("%s mentioned you").printf (account.display_name);
case REBLOG:
return _("%s boosted your toot").printf (account.display_name);
case FAVORITE:
return _("%s favorited your toot").printf (account.display_name);
case FOLLOW:
return _("%s now follows you").printf (account.display_name);
case FOLLOW_REQUEST:
return _("%s wants to follow you").printf (account.display_name);
default:
assert_not_reached();
}
}
public string get_icon () {
switch (this) {

View File

@ -5,8 +5,12 @@ using Json;
public class Tootle.NetManager : GLib.Object {
public abstract signal void started();
public abstract signal void finished();
public abstract signal void started ();
public abstract signal void finished ();
public abstract signal void notification (Notification notification);
public abstract signal void status_added (Status status);
public abstract signal void status_removed (int64 id);
private int requests_processing = 0;
private Soup.Session session;
@ -49,7 +53,7 @@ public class Tootle.NetManager : GLib.Object {
return;
}
notificator = new Notificator (acc);
//notificator.start ();
notificator.start ();
});
}
@ -85,11 +89,9 @@ public class Tootle.NetManager : GLib.Object {
default:
break;
}
if (cb != null)
cb (sess, mess);
msg.request_body.free ();
msg.response_body.free ();
});
return msg;
}

View File

@ -14,10 +14,8 @@ public class Tootle.Notificator : GLib.Object {
public async void start () {
var msg = account.get_stream ();
connection = yield Tootle.network.stream (msg);
connection.error.connect (e => error (e.message));
connection.message.connect ((i, bytes) => {
warning ((string)bytes.get_data ());
});
connection.error.connect (on_error);
connection.message.connect (on_message);
debug ("Receiving notifications for %lld", account.id);
}
@ -26,4 +24,56 @@ public class Tootle.Notificator : GLib.Object {
connection.close (0, null);
}
private void on_error (Error e) {
error (e.message);
}
private void on_message (int i, Bytes bytes) {
var network = Tootle.network;
var msg = (string) bytes.get_data ();
var parser = new Json.Parser ();
parser.load_from_data (msg, -1);
var root = parser.get_root ().get_object ();
var type = root.get_string_member ("event");
switch (type) {
case "update":
var status = Status.parse (sanitize (root));
network.status_added (status);
break;
case "delete":
var id = int64.parse (root.get_string_member("payload"));
network.status_removed (id);
break;
case "notification":
var notif = Notification.parse (sanitize (root));
toast (notif);
network.notification (notif);
break;
default:
warning ("Unknown push event: %s", type);
break;
}
}
private Json.Object sanitize (Json.Object root) {
var payload = root.get_string_member ("payload");
var sanitized = Soup.URI.decode (payload);
var parser = new Json.Parser ();
parser.load_from_data (sanitized, -1);
return parser.get_root ().get_object ();
}
private void toast (Notification obj) {
var notification = new GLib.Notification (obj.type.get_desc_plain (obj.account));
if (obj.status != null) {
var desc = obj.status.content;
Regex tags = new Regex("<(.|\n)*?>", RegexCompileFlags.CASELESS);
notification.set_body (tags.replace(desc, -1, 0, ""));
}
Tootle.app.send_notification (Tootle.app.application_id + ":" + obj.id.to_string (), notification);
}
}

View File

@ -9,6 +9,7 @@ public class Tootle.NotificationsView : Tootle.AbstractView {
view.remove.connect (on_remove);
Tootle.accounts.switched.connect(on_account_changed);
Tootle.app.refresh.connect(on_refresh);
Tootle.network.notification.connect (notification => prepend (notification));
request ();
}
@ -21,18 +22,18 @@ public class Tootle.NotificationsView : Tootle.AbstractView {
return _("Notifications");
}
public void prepend(Notification notification){
public void prepend (Notification notification, bool invert_order = false) {
var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
separator.show ();
var widget = new NotificationWidget(notification);
widget.separator = separator;
image.icon_name = "notification-new-symbolic";
view.pack_start(separator, false, false, 0);
view.pack_start(widget, false, false, 0);
image.icon_name = "notification-new-symbolic";
}
public virtual void on_remove (Widget widget){
public virtual void on_remove (Widget widget) {
if (!(widget is NotificationWidget))
return;
@ -40,19 +41,19 @@ public class Tootle.NotificationsView : Tootle.AbstractView {
image.icon_name = get_icon ();
}
public virtual void on_refresh (){
public virtual void on_refresh () {
clear ();
request ();
}
public virtual void on_account_changed (Account? account){
public virtual void on_account_changed (Account? account) {
if(account == null)
return;
on_refresh ();
}
public void request (){
public void request () {
var url = "%s/api/v1/follow_requests".printf (Tootle.settings.instance_url);
var msg = new Soup.Message("GET", url);
Tootle.network.queue(msg, (sess, mess) => {

View File

@ -40,6 +40,13 @@ public class Tootle.NotificationWidget : Gtk.Grid {
label.label = notification.type.get_desc (notification.account);
get_style_context ().add_class ("notification");
if (notification.status != null) {
Tootle.network.status_removed.connect (id => {
if (id == notification.status.id)
destroy ();
});
}
destroy.connect (() => {
if(separator != null)
separator.destroy ();

View File

@ -179,6 +179,11 @@ public class Tootle.StatusWidget : Gtk.EventBox {
separator.destroy ();
});
Tootle.network.status_removed.connect (id => {
if (id == status.id)
destroy ();
});
rebind ();
}