Push notifications
This commit is contained in:
parent
ae1d615803
commit
44aa22c06e
|
@ -10,3 +10,4 @@ Categories=GNOME;GTK;Network;
|
|||
Keywords=toot;mastodon;social;network;post;
|
||||
MimeType=text/plain;
|
||||
StartupNotify=true
|
||||
X-GNOME-UsesNotifications=true
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -179,6 +179,11 @@ public class Tootle.StatusWidget : Gtk.EventBox {
|
|||
separator.destroy ();
|
||||
});
|
||||
|
||||
Tootle.network.status_removed.connect (id => {
|
||||
if (id == status.id)
|
||||
destroy ();
|
||||
});
|
||||
|
||||
rebind ();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue