1
0
mirror of https://gitlab.gnome.org/World/tootle synced 2025-02-08 23:58:45 +01:00

Fix circular references

This commit is contained in:
Bleak Grey 2020-07-10 17:22:38 +03:00 committed by GitHub
parent 92dd1e044a
commit 3d0bd9e48e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 128 additions and 88 deletions

View File

@ -46,8 +46,10 @@ public class Tootle.API.Account : Entity, Widgetizable {
return new Request.GET ("/api/v1/accounts/relationships")
.with_account (accounts.active)
.with_param ("id", id.to_string ())
.then_parse_array (node => {
rs = API.Relationship.from (node);
.then ((sess, msg) => {
Network.parse_array (msg, node => {
rs = API.Relationship.from (node);
});
})
.on_error (network.on_error)
.exec ();

View File

@ -4,11 +4,14 @@ using Gee;
public class Tootle.Request : Soup.Message {
public string url { set; get; }
private Network.SuccessCallback? cb;
private Network.ErrorCallback? error_cb;
private HashMap<string, string>? pars;
private weak InstanceAccount? account;
private bool needs_token = false;
Network.SuccessCallback? cb;
Network.ErrorCallback? error_cb;
HashMap<string, string>? pars;
weak InstanceAccount? account;
bool needs_token = false;
weak Gtk.Widget? ctx;
bool has_ctx = false;
public Request.GET (string url) {
Object (method: "GET", url: url);
@ -20,23 +23,22 @@ public class Tootle.Request : Soup.Message {
Object (method: "DELETE", url: url);
}
public Request with_ctx (Gtk.Widget ctx) {
this.has_ctx = true;
this.ctx = ctx;
this.ctx.destroy.connect (() => {
network.cancel (this);
this.ctx = null;
});
return this;
}
public Request then (owned Network.SuccessCallback cb) {
this.cb = (owned) cb;
return this;
}
public Request then_parse_array (owned Network.NodeCallback _cb) {
this.cb = (sess, msg) => {
var parser = new Json.Parser ();
parser.load_from_data ((string) msg.response_body.flatten ().data, -1);
parser.get_root ().get_array ().foreach_element ((array, i, node) => _cb (node, msg));
};
return this;
}
public Request then_parse_obj (owned Network.ObjectCallback _cb) {
this.cb = (sess, msg) => {
_cb (network.parse (msg));
this.cb = (s, m) => {
Idle.add (() => {
cb (s, m);
return false;
});
};
return this;
}
@ -60,8 +62,7 @@ public class Tootle.Request : Soup.Message {
return this;
}
// Should be used for requests with default priority
public Request queue () {
public Request exec () {
var parameters = "";
if (pars != null) {
parameters = "?";
@ -100,10 +101,4 @@ public class Tootle.Request : Soup.Message {
return this;
}
// Should be used for real-time user interactions (liking, removing and browsing posts)
public Request exec () {
this.priority = MessagePriority.HIGH;
return this.queue ();
}
}

View File

@ -26,9 +26,9 @@ public class Tootle.Cache : GLib.Object {
protected class Item : GLib.Object {
public Pixbuf data { get; construct set; }
public int64 references { get; construct set; }
public int references { get; construct set; }
public Item (Pixbuf d, int64 r) {
public Item (Pixbuf d, int r) {
Object (data: d, references: r);
}
}
@ -45,12 +45,14 @@ public class Tootle.Cache : GLib.Object {
return;
item.references--;
//info (@"DEREF $(r.key) $(item.references)");
if (item.references <= 0) {
//info ("REMOVE %s", r.key);
// message (@"[X] $(r.key)");
items.remove (r.key);
items_in_progress.remove (r.key);
}
// else {
// message (@"[-] $(r.key) - $(item.references)");
// }
}
public void load (string? url, owned CachedResultCallback cb) {
@ -59,9 +61,9 @@ public class Tootle.Cache : GLib.Object {
var key = url;
if (items.contains (key)) {
//info (@"LOAD $key");
var item = items.@get (key);
item.references++;
// message (@"[+] $key - $(item.references)");
cb (Reference () {
data = item.data,
key = key,
@ -72,19 +74,19 @@ public class Tootle.Cache : GLib.Object {
//var item = items.@get (key);
var message = items_in_progress.@get (key);
if (message == null) {
message = new Soup.Message ("GET", url);
var msg = items_in_progress.@get (key);
if (msg == null) {
msg = new Soup.Message ("GET", url);
ulong id = 0;
id = message.finished.connect (() => {
id = msg.finished.connect (() => {
Pixbuf? pixbuf = null;
var data = message.response_body.flatten ().data;
var data = msg.response_body.flatten ().data;
var stream = new MemoryInputStream.from_data (data);
pixbuf = new Pixbuf.from_stream (stream);
stream.close ();
//info (@"< STORE $key");
// message (@"[*] $key");
items[key] = new Item (pixbuf, 1);
items_in_progress.remove (key);
@ -94,10 +96,10 @@ public class Tootle.Cache : GLib.Object {
loading = false
});
message.disconnect (id);
msg.disconnect (id);
});
network.queue (message, (sess, msg) => {
network.queue (msg, (sess, mess) => {
// no one cares
},
(code, reason) => {
@ -110,12 +112,12 @@ public class Tootle.Cache : GLib.Object {
loading = true
});
items_in_progress.insert (key, message);
items_in_progress.insert (key, msg);
}
else {
//info ("AWAIT: %s", key);
//message ("[/]: %s", key);
ulong id = 0;
id = message.finished.connect_after (() => {
id = msg.finished.connect_after (() => {
var it = items.@get (key);
cb (Reference () {
data = it.data,
@ -123,13 +125,13 @@ public class Tootle.Cache : GLib.Object {
loading = false
});
it.references++;
message.disconnect (id);
msg.disconnect (id);
});
}
}
public void clear () {
info ("PURGE");
// message ("[ CLEARED ALL ]");
items.remove_all ();
items_in_progress.remove_all ();
}

View File

@ -1,10 +1,24 @@
public interface Tootle.IAccountListener : GLib.Object {
protected void connect_account () {
accounts.notify["active"].connect (() => on_account_changed (accounts.active));
accounts.saved.notify["size"].connect (() => on_accounts_changed (accounts.saved));
//TODO: Refactor into AccountHolder
protected void account_listener_init () {
accounts.notify["active"].connect (_on_active_acc_update);
accounts.saved.notify["size"].connect (_on_saved_accs_update);
on_account_changed (accounts.active);
}
protected void account_listener_free () {
accounts.notify["active"].disconnect (_on_active_acc_update);
accounts.saved.notify["size"].disconnect (_on_saved_accs_update);
}
void _on_active_acc_update (ParamSpec s) {
on_account_changed (accounts.active);
}
void _on_saved_accs_update (ParamSpec s) {
on_accounts_changed (accounts.saved);
}
public virtual void on_account_changed (InstanceAccount? account) {}
public virtual void on_accounts_changed (Gee.ArrayList<InstanceAccount> accounts) {}

View File

@ -29,17 +29,18 @@ public class Tootle.Network : GLib.Object {
});
}
// public void cancel_request (Soup.Message? msg) {
// if (msg == null)
// return;
public void cancel (Soup.Message? msg) {
if (msg == null)
return;
// switch (msg.status_code) {
// case Soup.Status.CANCELLED:
// case Soup.Status.OK:
// return;
// }
// session.cancel_message (msg, Soup.Status.CANCELLED);
// }
switch (msg.status_code) {
case Soup.Status.CANCELLED:
case Soup.Status.OK:
return;
}
debug ("Cancelling message");
session.cancel_message (msg, Soup.Status.CANCELLED);
}
public void queue (owned Soup.Message message, owned SuccessCallback? cb, owned ErrorCallback? errcb = null) {
requests_processing++;
@ -57,6 +58,9 @@ public class Tootle.Network : GLib.Object {
errcb (Soup.Status.NONE, e.message);
}
}
else if (status == Soup.Status.CANCELLED) {
debug ("Message is cancelled. Ignoring callback invocation.");
}
else {
if (errcb != null)
errcb ((int32)status, describe_error ((int32)status));
@ -89,4 +93,12 @@ public class Tootle.Network : GLib.Object {
return parse_node (msg).get_object ();
}
public static void parse_array (Soup.Message msg, owned NodeCallback cb) throws Error {
var parser = new Json.Parser ();
parser.load_from_data ((string) msg.response_body.flatten ().data, -1);
parser.get_root ().get_array ().foreach_element ((array, i, node) => {
cb (node, msg);
});
}
}

View File

@ -71,8 +71,8 @@ public class Tootle.Views.Base : Box {
}
public virtual void clear (){
content_list.forall (widget => {
widget.destroy ();
content_list.forall (w => {
w.destroy ();
});
state = "status";
}

View File

@ -11,7 +11,7 @@ public class Tootle.Views.ExpandedStatus : Views.Base, IAccountListener {
root_status: status,
status_message: STATUS_LOADING
);
connect_account ();
account_listener_init ();
}
public override void on_account_changed (InstanceAccount? acc) {
@ -38,8 +38,9 @@ public class Tootle.Views.ExpandedStatus : Views.Base, IAccountListener {
public void request () {
new Request.GET (@"/api/v1/statuses/$(root_status.id)/context")
.with_account (account)
.then_parse_obj (root => {
if (scrolled == null) return;
.with_ctx (this)
.then ((sess, msg) => {
var root = network.parse (msg);
var ancestors = root.get_array_member ("ancestors");
ancestors.foreach_element ((array, i, node) => {

View File

@ -12,6 +12,8 @@ public class Tootle.Views.Profile : Views.Timeline {
Button rs_button;
Label rs_button_label;
weak ListBoxRow note_row;
public bool exclude_replies { get; set; default = true; }
public bool only_media { get; set; default = false; }
@ -39,7 +41,7 @@ public class Tootle.Views.Profile : Views.Timeline {
return true;
});
var note_row = builder.get_object ("note_row") as ListBoxRow;
note_row = builder.get_object ("note_row") as ListBoxRow;
var note = builder.get_object ("note") as Widgets.RichLabel;
profile.bind_property ("note", note, "text", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
var text = Html.simplify ((string) src);
@ -83,6 +85,9 @@ public class Tootle.Views.Profile : Views.Timeline {
);
profile.get_relationship ();
}
~Profile () {
filter.destroy ();
}
public override void on_shown () {
window.header.custom_title = filter;

View File

@ -17,7 +17,7 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba
construct {
app.refresh.connect (on_refresh);
status_button.clicked.connect (on_refresh);
connect_account ();
account_listener_init ();
on_status_added.connect (add_status);
on_status_removed.connect (remove_status);
@ -92,20 +92,22 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba
public virtual bool request () {
var req = append_params (new Request.GET (get_req_url ()))
.with_account (account)
.then_parse_array ((node, msg) => {
try {
var e = Entity.from_json (accepts, node);
var w = e as Widgetizable;
append (w.to_widget ());
}
catch (Error e) {
warning (@"Timeline item parse error: $(e.message)");
}
.with_ctx (this)
.then ((sess, msg) => {
Network.parse_array (msg, node => {
try {
var e = Entity.from_json (accepts, node);
var w = e as Widgetizable;
append (w.to_widget ());
}
catch (Error e) {
warning (@"Timeline item parse error: $(e.message)");
}
get_pages (msg.response_headers.get_one ("Link"));
});
})
.on_error (on_error);
req.finished.connect (() => {
get_pages (req.response_headers.get_one ("Link"));
});
req.exec ();
return GLib.Source.REMOVE;
}

View File

@ -64,7 +64,7 @@ public class Tootle.Widgets.AccountsButton : Gtk.MenuButton, IAccountListener {
Button item_bookmarks;
construct {
connect_account ();
account_listener_init ();
item_refresh.clicked.connect (() => {
app.refresh ();
@ -101,6 +101,9 @@ public class Tootle.Widgets.AccountsButton : Gtk.MenuButton, IAccountListener {
account_list.row_activated.connect (on_selection_changed);
}
~AccountsButton () {
account_listener_free ();
}
protected void on_selection_changed (ListBoxRow r) {
var i = r.get_index ();

View File

@ -12,7 +12,7 @@ public class Tootle.Widgets.Avatar : EventBox {
get_style_context ().add_class ("avatar");
notify["url"].connect (on_url_updated);
notify["size"].connect (on_redraw);
Screen.get_default ().monitors_changed.connect (on_redraw);
// Screen.get_default ().monitors_changed.connect (on_redraw);
on_url_updated ();
}
@ -23,11 +23,13 @@ public class Tootle.Widgets.Avatar : EventBox {
~Avatar () {
notify["url"].disconnect (on_url_updated);
Screen.get_default ().monitors_changed.disconnect (on_redraw);
// Screen.get_default ().monitors_changed.disconnect (on_redraw);
cache.unload (cached);
}
private void on_url_updated () {
if (cached != null)
cache.unload (cached);
cached = null;
on_redraw ();
cache.load (url, on_cache_result);
@ -39,8 +41,7 @@ public class Tootle.Widgets.Avatar : EventBox {
}
public int get_scaled_size () {
return size;
//return size * get_scale_factor ();
return size; //return size * get_scale_factor ();
}
private void on_redraw () {

View File

@ -112,7 +112,7 @@ public class Tootle.Widgets.Status : ListBoxRow {
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");

View File

@ -3,6 +3,8 @@ using Gtk;
[GtkTemplate (ui = "/com/github/bleakgrey/tootle/ui/widgets/timeline_filter.ui")]
public class Tootle.Widgets.TimelineFilter : MenuButton {
weak Views.Profile view;
[GtkChild]
public Label title;
@ -22,7 +24,8 @@ public class Tootle.Widgets.TimelineFilter : MenuButton {
radio_source.bind_property ("active", post_filter, "reveal-child", BindingFlags.SYNC_CREATE);
}
public TimelineFilter.with_profile (Views.Profile view) {
public TimelineFilter.with_profile (Views.Profile profile) {
this.view = profile;
radio_source.get_group ().@foreach (w => {
w.toggled.connect (() => {
if (w.active) {