Fix occasional broken RichLabels

This commit is contained in:
bleakgrey 2018-06-06 17:19:11 +03:00
parent 2756afe74b
commit a5c5ddbf04
7 changed files with 54 additions and 54 deletions

View File

@ -18,7 +18,6 @@ public class Tootle.Status {
public StatusVisibility visibility; public StatusVisibility visibility;
public Status? reblog; public Status? reblog;
public Mention[]? mentions; public Mention[]? mentions;
public Tag[]? tags;
public Attachment[]? attachments; public Attachment[]? attachments;
public Status(int64 id) { public Status(int64 id) {
@ -66,15 +65,6 @@ public class Tootle.Status {
if (_mentions.length > 0) if (_mentions.length > 0)
status.mentions = _mentions; status.mentions = _mentions;
Tag[]? _tags = {};
obj.get_array_member ("tags").foreach_element ((array, i, node) => {
var object = node.get_object ();
if (object != null)
_tags += Tag.parse (object);
});
if (_tags.length > 0)
status.tags = _tags;
Attachment[]? _attachments = {}; Attachment[]? _attachments = {};
obj.get_array_member ("media_attachments").foreach_element ((array, i, node) => { obj.get_array_member ("media_attachments").foreach_element ((array, i, node) => {
var object = node.get_object (); var object = node.get_object ();

View File

@ -1,20 +1,18 @@
public class Tootle.Desktop { public class Tootle.Desktop {
// open a URI in the user's default browser
// Open a URI in the user's default browser
public static void open_url (string url) { public static void open_url (string url) {
Gtk.show_uri (null, url, Gdk.CURRENT_TIME); Gtk.show_uri (null, url, Gdk.CURRENT_TIME);
} }
// copy a string to the clipboard // Copy a string to the clipboard
public static void copy (string str) { public static void copy (string str) {
var display = Tootle.window.get_display (); var display = window.get_display ();
var clipboard = Gtk.Clipboard.get_for_display (display, Gdk.SELECTION_CLIPBOARD); var clipboard = Gtk.Clipboard.get_for_display (display, Gdk.SELECTION_CLIPBOARD);
var normalized = str clipboard.set_text (RichLabel.restore_entities (str), -1);
.replace ("&", "&")
.replace ("'", "'");
clipboard.set_text (normalized, -1);
} }
// download a file from the web to a user's configured Downloads folder // Download a file from the web to a user's configured Downloads folder
public static void download_file (string url) { public static void download_file (string url) {
debug ("Downloading file: %s", url); debug ("Downloading file: %s", url);
@ -23,7 +21,7 @@ public class Tootle.Desktop {
if (name == null) if (name == null)
name = "unknown"; name = "unknown";
var dir_path = "%s/%s".printf (GLib.Environment.get_user_special_dir (UserDirectory.DOWNLOAD), Tootle.app.program_name); var dir_path = "%s/%s".printf (GLib.Environment.get_user_special_dir (UserDirectory.DOWNLOAD), app.program_name);
var file_path = "%s/%s".printf (dir_path, name); var file_path = "%s/%s".printf (dir_path, name);
var msg = new Soup.Message("GET", url); var msg = new Soup.Message("GET", url);
@ -39,12 +37,13 @@ public class Tootle.Desktop {
FileOutputStream stream = file.create (FileCreateFlags.PRIVATE); FileOutputStream stream = file.create (FileCreateFlags.PRIVATE);
stream.write (data); stream.write (data);
} }
Tootle.app.toast ("Media downloaded"); app.toast ("Media downloaded");
} catch (Error e) { } catch (Error e) {
Tootle.app.toast (e.message); app.toast (e.message);
warning ("Error: %s\n", e.message); warning ("Error: %s\n", e.message);
} }
}); });
Tootle.network.queue (msg); network.queue (msg);
} }
} }

View File

@ -1,4 +1,5 @@
public class Tootle.Html { public class Tootle.Html {
public static string remove_tags (string content) { public static string remove_tags (string content) {
var all_tags = new Regex("<(.|\n)*?>", RegexCompileFlags.CASELESS); var all_tags = new Regex("<(.|\n)*?>", RegexCompileFlags.CASELESS);
return all_tags.replace(content, -1, 0, ""); return all_tags.replace(content, -1, 0, "");
@ -20,15 +21,10 @@ public class Tootle.Html {
return simplified; return simplified;
} }
public static string escape_entities (string content) {
return content
.replace ("&", "&amp;")
.replace ("'", "&apos;");
}
public static string uri_encode (string content) { public static string uri_encode (string content) {
var to_escape = ";&+"; var to_escape = ";&+";
return Soup.URI.encode (content, to_escape); return Soup.URI.encode (content, to_escape);
} }
} }

View File

@ -10,10 +10,10 @@ public class Tootle.AccountView : TimelineView {
Gtk.Grid header_image; Gtk.Grid header_image;
Gtk.Box header_info; Gtk.Box header_info;
Granite.Widgets.Avatar avatar; Granite.Widgets.Avatar avatar;
Gtk.Label display_name; RichLabel display_name;
Gtk.Label username; Gtk.Label username;
Gtk.Label relationship; Gtk.Label relationship;
Tootle.RichLabel note; RichLabel note;
Gtk.Grid counters; Gtk.Grid counters;
Gtk.Box actions; Gtk.Box actions;
Gtk.Button button_follow; Gtk.Button button_follow;
@ -115,11 +115,11 @@ public class Tootle.AccountView : TimelineView {
add_counter (_("Toots"), 1, account.statuses_count); add_counter (_("Toots"), 1, account.statuses_count);
add_counter (_("Follows"), 2, account.following_count).clicked.connect (() => { add_counter (_("Follows"), 2, account.following_count).clicked.connect (() => {
var view = new FollowingView (ref account); var view = new FollowingView (ref account);
Tootle.window.open_view (view); window.open_view (view);
}); });
add_counter (_("Followers"), 3, account.followers_count).clicked.connect (() => { add_counter (_("Followers"), 3, account.followers_count).clicked.connect (() => {
var view = new FollowersView (ref account); var view = new FollowersView (ref account);
Tootle.window.open_view (view); window.open_view (view);
}); });
show_all (); show_all ();
@ -141,11 +141,11 @@ public class Tootle.AccountView : TimelineView {
public void rebind (){ public void rebind (){
display_name.label = "<b>%s</b>".printf (Html.escape_entities(account.display_name)); display_name.set_label ("<b>%s</b>".printf (account.display_name));
username.label = "@" + account.acct; username.label = "@" + account.acct;
note.label = Html.simplify (account.note); note.set_label (Html.simplify (account.note));
button_follow.visible = !account.is_self (); button_follow.visible = !account.is_self ();
Tootle.network.load_avatar (account.avatar, avatar, 128); network.load_avatar (account.avatar, avatar, 128);
menu_edit.visible = account.is_self (); menu_edit.visible = account.is_self ();
@ -214,7 +214,7 @@ public class Tootle.AccountView : TimelineView {
if (page_next != null) if (page_next != null)
return page_next; return page_next;
var url = "%s/api/v1/accounts/%lld/statuses?limit=%i".printf (Tootle.accounts.formal.instance, account.id, this.limit); var url = "%s/api/v1/accounts/%lld/statuses?limit=%i".printf (accounts.formal.instance, account.id, this.limit);
return url; return url;
} }
@ -237,7 +237,7 @@ public class Tootle.AccountView : TimelineView {
} }
public static void open_from_id (int64 id){ public static void open_from_id (int64 id){
var url = "%s/api/v1/accounts/%lld".printf (Tootle.accounts.formal.instance, id); var url = "%s/api/v1/accounts/%lld".printf (accounts.formal.instance, id);
var msg = new Soup.Message("GET", url); var msg = new Soup.Message("GET", url);
msg.priority = Soup.MessagePriority.HIGH; msg.priority = Soup.MessagePriority.HIGH;
network.queue (msg, (sess, mess) => { network.queue (msg, (sess, mess) => {
@ -254,7 +254,7 @@ public class Tootle.AccountView : TimelineView {
} }
public static void open_from_name (string name){ public static void open_from_name (string name){
var url = "%s/api/v1/accounts/search?limit=1&q=%s".printf (Tootle.accounts.formal.instance, name); var url = "%s/api/v1/accounts/search?limit=1&q=%s".printf (accounts.formal.instance, name);
var msg = new Soup.Message("GET", url); var msg = new Soup.Message("GET", url);
msg.priority = Soup.MessagePriority.HIGH; msg.priority = Soup.MessagePriority.HIGH;
network.queue (msg, (sess, mess) => { network.queue (msg, (sess, mess) => {

View File

@ -5,11 +5,11 @@ public class Tootle.NotificationWidget : Gtk.Grid {
private Notification notification; private Notification notification;
public Gtk.Separator? separator; public Separator? separator;
private Gtk.Image image; private Image image;
private Tootle.RichLabel label; private RichLabel label;
private StatusWidget? status_widget; private StatusWidget? status_widget;
private Gtk.Button dismiss; private Button dismiss;
construct { construct {
margin = 6; margin = 6;
@ -37,7 +37,7 @@ public class Tootle.NotificationWidget : Gtk.Grid {
public NotificationWidget (Notification notification) { public NotificationWidget (Notification notification) {
this.notification = notification; this.notification = notification;
image.icon_name = notification.type.get_icon (); image.icon_name = notification.type.get_icon ();
label.label = notification.type.get_desc (notification.account); label.set_label (notification.type.get_desc (notification.account));
get_style_context ().add_class ("notification"); get_style_context ().add_class ("notification");
if (notification.status != null) { if (notification.status != null) {

View File

@ -5,11 +5,27 @@ public class Tootle.RichLabel : Gtk.Label {
public weak Mention[]? mentions; public weak Mention[]? mentions;
public RichLabel (string text) { public RichLabel (string text) {
label = text; set_label (text);
set_use_markup (true); set_use_markup (true);
activate_link.connect (open_link); activate_link.connect (open_link);
} }
public static string escape_entities (string content) {
return content
.replace ("&", "&amp;")
.replace ("'", "&apos;");
}
public static string restore_entities (string content) {
return content
.replace ("&amp;", "&")
.replace ("&apos;", "'");
}
public new void set_label (string text) {
base.set_markup (escape_entities (text));
}
public void wrap_words () { public void wrap_words () {
halign = Gtk.Align.START; halign = Gtk.Align.START;
single_line_mode = false; single_line_mode = false;

View File

@ -11,12 +11,12 @@ public class Tootle.StatusWidget : Gtk.EventBox {
public Gtk.Separator? separator; public Gtk.Separator? separator;
public Gtk.Grid grid; public Gtk.Grid grid;
public Granite.Widgets.Avatar avatar; public Granite.Widgets.Avatar avatar;
public Gtk.Label title_user; public RichLabel title_user;
public Gtk.Label title_date; public Gtk.Label title_date;
public Gtk.Label title_acct; public Gtk.Label title_acct;
public Gtk.Revealer revealer; public Gtk.Revealer revealer;
public Tootle.RichLabel content_label; public RichLabel content_label;
public Tootle.RichLabel? content_spoiler; public RichLabel? content_spoiler;
public Gtk.Button? spoiler_button; public Gtk.Button? spoiler_button;
public Gtk.Box title_box; public Gtk.Box title_box;
public AttachmentBox attachments; public AttachmentBox attachments;
@ -41,8 +41,7 @@ public class Tootle.StatusWidget : Gtk.EventBox {
title_box.margin_end = 12; title_box.margin_end = 12;
title_box.margin_top = 6; title_box.margin_top = 6;
title_user = new Gtk.Label (""); title_user = new RichLabel ("");
title_user.use_markup = true;
title_box.pack_start (title_user, false, false, 0); title_box.pack_start (title_user, false, false, 0);
title_acct = new Gtk.Label (""); title_acct = new Gtk.Label ("");
@ -180,7 +179,7 @@ public class Tootle.StatusWidget : Gtk.EventBox {
separator.destroy (); separator.destroy ();
}); });
Tootle.network.status_removed.connect (id => { network.status_removed.connect (id => {
if (id == this.status.id) if (id == this.status.id)
destroy (); destroy ();
}); });
@ -200,7 +199,7 @@ public class Tootle.StatusWidget : Gtk.EventBox {
public void rebind () { public void rebind () {
var formal = status.get_formal (); var formal = status.get_formal ();
title_user.label = "<b>%s</b>".printf (Html.escape_entities (formal.account.display_name)); title_user.set_label ("<b>%s</b>".printf ((formal.account.display_name)));
title_acct.label = "@" + formal.account.acct; title_acct.label = "@" + formal.account.acct;
content_label.label = formal.content; content_label.label = formal.content;
content_label.mentions = formal.mentions; content_label.mentions = formal.mentions;
@ -224,7 +223,7 @@ public class Tootle.StatusWidget : Gtk.EventBox {
reblog.tooltip_text = _("This post can't be boosted"); reblog.tooltip_text = _("This post can't be boosted");
} }
Tootle.network.load_avatar (formal.account.avatar, avatar, get_avatar_size ()); network.load_avatar (formal.account.avatar, avatar, get_avatar_size ());
} }
public bool is_spoiler () { public bool is_spoiler () {
@ -241,14 +240,14 @@ public class Tootle.StatusWidget : Gtk.EventBox {
public bool open_account () { public bool open_account () {
var view = new AccountView (status.get_formal ().account); var view = new AccountView (status.get_formal ().account);
Tootle.window.open_view (view); window.open_view (view);
return true; return true;
} }
public bool open (EventButton ev) { public bool open (EventButton ev) {
var formal = status.get_formal (); var formal = status.get_formal ();
var view = new StatusView (ref formal); var view = new StatusView (ref formal);
Tootle.window.open_view (view); window.open_view (view);
return true; return true;
} }