diff --git a/src/API/Status.vala b/src/API/Status.vala index 2b6bd92..8a1e767 100644 --- a/src/API/Status.vala +++ b/src/API/Status.vala @@ -86,6 +86,10 @@ public class Tootle.Status { return status; } + public bool is_owned (){ + return get_formal ().account.id == Tootle.accounts.current.id; + } + public void set_reblogged (bool rebl = true){ var action = rebl ? "reblog" : "unreblog"; var msg = new Soup.Message("POST", "%s/api/v1/statuses/%lld/%s".printf (Tootle.settings.instance_url, id, action)); diff --git a/src/Utils.vala b/src/Utils.vala index 6ee7695..1b89dda 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -27,7 +27,18 @@ public class Tootle.Utils{ } public static string escape_entities (string content) { - return content.replace ("&", "&"); + return content + .replace ("&", "&") + .replace ("'", "'"); + } + + public static void copy (string str) { + var display = Tootle.window.get_display (); + var clipboard = Gtk.Clipboard.get_for_display (display, Gdk.SELECTION_CLIPBOARD); + var normalized = str + .replace ("&", "&") + .replace ("'", "'"); + clipboard.set_text (normalized, -1); } } diff --git a/src/Views/AccountView.vala b/src/Views/AccountView.vala index 2e80e49..01e9329 100644 --- a/src/Views/AccountView.vala +++ b/src/Views/AccountView.vala @@ -176,6 +176,10 @@ public class Tootle.AccountView : TimelineView { relationship.hide (); } + public override bool is_status_owned (ref Status status) { + return status.get_formal().account.id == account.id; + } + private Gtk.Button add_counter (string name, int? i = null, int64? val = null) { Gtk.Button btn; if (val != null){ @@ -201,10 +205,6 @@ public class Tootle.AccountView : TimelineView { return view.get_children ().length () <= 2; } - public override bool is_status_owned (Status status){ - return status.get_formal ().account.id == account.id; - } - public override string get_url () { if (page_next != null) return page_next; diff --git a/src/Views/StatusView.vala b/src/Views/StatusView.vala index 82b05c8..aaa971a 100644 --- a/src/Views/StatusView.vala +++ b/src/Views/StatusView.vala @@ -14,14 +14,14 @@ public class Tootle.StatusView : AbstractView { private void prepend (ref Status status, bool is_root = false){ var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL); separator.show (); - var widget = new StatusWidget (ref status); - if (is_root) - widget.highlight (); - widget.content_label.selectable = true; - if (widget.content_spoiler != null) - widget.content_spoiler.selectable = true; - widget.avatar.button_press_event.connect(widget.on_avatar_clicked); + var widget = new StatusWidget (ref status); + widget.avatar.button_press_event.connect(widget.open_account); + if (!is_root) + widget.button_press_event.connect(widget.open); + else + widget.highlight (); + if (!last_was_a_root) { widget.separator = separator; view.pack_start (separator, false, false, 0); diff --git a/src/Views/TimelineView.vala b/src/Views/TimelineView.vala index 0cc458f..f1ef6be 100644 --- a/src/Views/TimelineView.vala +++ b/src/Views/TimelineView.vala @@ -31,10 +31,6 @@ public class Tootle.TimelineView : AbstractView { return _("Home"); } - public virtual bool is_status_owned (Status status){ - return false; - } - private void on_status_added (ref Status status, string timeline) { if (timeline != this.timeline) return; @@ -42,6 +38,10 @@ public class Tootle.TimelineView : AbstractView { prepend (ref status, true); } + public virtual bool is_status_owned (ref Status status) { + return status.is_owned (); + } + public void prepend (ref Status status, bool first = false){ if (empty != null) empty.destroy (); @@ -52,8 +52,8 @@ public class Tootle.TimelineView : AbstractView { var widget = new StatusWidget (ref status); widget.separator = separator; widget.button_press_event.connect(widget.open); - if (!is_status_owned (status)) - widget.avatar.button_press_event.connect(widget.on_avatar_clicked); + if (!is_status_owned (ref status)) + widget.avatar.button_press_event.connect(widget.open_account); view.pack_start(separator, false, false, 0); view.pack_start(widget, false, false, 0); diff --git a/src/Widgets/AccountWidget.vala b/src/Widgets/AccountWidget.vala index 1b99771..6fe94ed 100644 --- a/src/Widgets/AccountWidget.vala +++ b/src/Widgets/AccountWidget.vala @@ -12,7 +12,7 @@ public class Tootle.AccountWidget : StatusWidget { title_acct.visible = false; content_label.margin_bottom = 12; button_press_event.connect(() => { - on_avatar_clicked (); + open_account (); return true; }); } diff --git a/src/Widgets/NotificationWidget.vala b/src/Widgets/NotificationWidget.vala index 857a006..72c2fa4 100644 --- a/src/Widgets/NotificationWidget.vala +++ b/src/Widgets/NotificationWidget.vala @@ -55,7 +55,7 @@ public class Tootle.NotificationWidget : Gtk.Grid { if (notification.status != null){ status_widget = new StatusWidget (ref notification.status); status_widget.button_press_event.connect(status_widget.open); - status_widget.avatar.button_press_event.connect(status_widget.on_avatar_clicked); + status_widget.avatar.button_press_event.connect(status_widget.open_account); attach(status_widget, 1, 3, 3, 1); } diff --git a/src/Widgets/StatusWidget.vala b/src/Widgets/StatusWidget.vala index 4a0a0ce..d12032e 100644 --- a/src/Widgets/StatusWidget.vala +++ b/src/Widgets/StatusWidget.vala @@ -1,4 +1,5 @@ using Gtk; +using Gdk; using Granite; public class Tootle.StatusWidget : Gtk.EventBox { @@ -107,6 +108,8 @@ public class Tootle.StatusWidget : Gtk.EventBox { grid.attach (revealer, 2, 4, 1, 1); grid.attach (counters, 2, 5, 1, 1); show_all (); + + this.button_press_event.connect (on_clicked); } public StatusWidget (ref Status status) { @@ -231,17 +234,51 @@ public class Tootle.StatusWidget : Gtk.EventBox { return null; } - public bool on_avatar_clicked () { + public bool open_account () { var view = new AccountView (status.get_formal ().account); Tootle.window.open_view (view); return true; } - public bool open () { + public bool open (EventButton ev) { var formal = status.get_formal (); var view = new StatusView (ref formal); Tootle.window.open_view (view); - return false; + return true; + } + + private bool on_clicked (EventButton ev) { + if (ev.button == 3) + return open_menu (ev.button, ev.time); + else + return false; + } + + public bool open_menu (uint button, uint32 time) { + var menu = new Gtk.Menu (); + menu.selection_done.connect (() => { + menu.detach (); + menu.destroy (); + }); + + var item_open_link = new Gtk.MenuItem.with_label (_("Open in Browser")); + item_open_link.activate.connect (() => Utils.open_url (status.url)); + var item_copy_link = new Gtk.MenuItem.with_label (_("Copy Link")); + item_copy_link.activate.connect (() => Utils.copy (status.url)); + var item_copy = new Gtk.MenuItem.with_label (_("Copy Text")); + item_copy.activate.connect (() => { + var sanitized = Utils.escape_html (status.content); + Utils.copy (sanitized); + }); + menu.add (item_open_link); + menu.add (new Gtk.SeparatorMenuItem ()); + menu.add (item_copy_link); + menu.add (item_copy); + + menu.show_all (); + menu.attach_widget = this; + menu.popup (null, null, null, button, time); + return true; } }