Fix infinite loop with status actions

This commit is contained in:
Bleak Grey 2021-02-02 16:34:36 +03:00
parent 9b0229e4cc
commit f485a6d505
3 changed files with 52 additions and 30 deletions

View File

@ -22,7 +22,11 @@ public class Tootle.Entity : GLib.Object, Widgetizable, Json.Serializable {
}
public void patch (GLib.Object with) {
foreach (ParamSpec spec in with.get_class ().list_properties ()) {
patch_specs (with, with.get_class ().list_properties ());
}
public void patch_specs (GLib.Object with, ParamSpec[] specs) {
foreach (ParamSpec spec in specs) {
var name = spec.get_name ();
var defined = get_class ().find_property (name) != null;
if (defined && is_spec_valid (ref spec)) {

View File

@ -108,16 +108,8 @@ public class Tootle.API.Status : Entity, Widgetizable {
return result;
}
public void action (string action, owned Network.ErrorCallback? err = network.on_error) {
new Request.POST (@"/api/v1/statuses/$(formal.id)/$action")
.with_account (accounts.active)
.then ((sess, msg) => {
var node = network.parse_node (msg);
var upd = API.Status.from (node).formal;
patch (upd);
})
.on_error ((status, reason) => err (status, reason))
.exec ();
public Request action (string action) {
return new Request.POST (@"/api/v1/statuses/$(formal.id)/$action").with_account (accounts.active);
}
public Request annihilate () {

View File

@ -118,20 +118,9 @@ public class Tootle.Widgets.Status : ListBoxRow {
kind = API.NotificationType.REBLOG_REMOTE_USER;
}
status.formal.bind_property ("favourited", favorite_button, "active", BindingFlags.SYNC_CREATE);
favorite_button.clicked.connect (() => {
status.action (status.formal.favourited ? "unfavourite" : "favourite");
});
status.formal.bind_property ("reblogged", reblog_button, "active", BindingFlags.SYNC_CREATE);
reblog_button.clicked.connect (() => {
status.action (status.formal.reblogged ? "unreblog" : "reblog");
});
status.formal.bind_property ("bookmarked", bookmark_button, "active", BindingFlags.SYNC_CREATE);
bookmark_button.clicked.connect (() => {
status.action (status.formal.bookmarked ? "unbookmark" : "bookmark");
});
bind_toggleable_prop (favorite_button, "favourited", "favourite", "unfavourite");
bind_toggleable_prop (reblog_button, "reblogged", "reblog", "unreblog");
bind_toggleable_prop (bookmark_button, "bookmarked", "bookmark", "unbookmark");
reply_button.clicked.connect (() => new Dialogs.Compose.reply (status));
if (status.formal.in_reply_to_id != null)
@ -166,11 +155,6 @@ public class Tootle.Widgets.Status : ListBoxRow {
if (status.id == "") {
actions.destroy ();
date_label.destroy ();
//TODO: this
// content.single_line_mode = true;
// content.lines = 2;
// content.ellipsize = Pango.EllipsizeMode.END;
}
if (!attachments.populate (status.formal.media_attachments) || status.id == "") {
@ -297,4 +281,46 @@ public class Tootle.Widgets.Status : ListBoxRow {
}
}
// This disables the button when its status property is updated.
// Fixes a bug where clicking one or more post action buttons
// triggers an infite loop of network requests.
//
// This took me an entire day to fix and I'm quite sad.
public void bind_toggleable_prop (ToggleButton button, string prop, string on, string off) {
var init_val = Value (Type.BOOLEAN);
((GLib.Object) status.formal).get_property (prop, ref init_val);
button.active = init_val.get_boolean ();
status.formal.bind_property (prop, button, "active", BindingFlags.SYNC_CREATE);
button.toggled.connect (() => {
if (!(button.has_focus && button.sensitive))
return;
button.sensitive = false;
var val = Value (Type.BOOLEAN);
((GLib.Object) status.formal).get_property (prop, ref val);
var act = val.get_boolean () ? off : on;
var req = status.action (act);
req.await.begin ((obj, res) => {
try {
var msg = req.await.end (res);
var node = network.parse_node (msg);
var entity = API.Status.from (node);
var new_val = Value (Type.BOOLEAN);
((GLib.Object) entity.formal).get_property (prop, ref new_val);
((GLib.Object) status.formal).set_property (prop, new_val.get_boolean ());
}
catch (Error e) {
warning (@"Couldn't perform action \"$act\" on a Status:");
warning (e.message);
app.inform (Gtk.MessageType.WARNING, _("Network Error"), e.message);
}
button.sensitive = true;
});
});
}
}