2018-04-14 12:09:06 +00:00
|
|
|
using Gtk;
|
2018-05-21 15:23:31 +00:00
|
|
|
using Gdk;
|
2018-04-14 12:09:06 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
[GtkTemplate (ui = "/com/github/bleakgrey/tootle/ui/widgets/status.ui")]
|
2019-03-11 14:14:37 +00:00
|
|
|
public class Tootle.Widgets.Status : EventBox {
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
public API.Status status { get; construct set; }
|
|
|
|
public API.NotificationType? kind { get; construct set; }
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
[GtkChild]
|
|
|
|
protected Separator separator;
|
|
|
|
[GtkChild]
|
2018-10-24 10:50:40 +00:00
|
|
|
protected Grid grid;
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
[GtkChild]
|
|
|
|
protected Image header_icon;
|
|
|
|
[GtkChild]
|
|
|
|
protected Widgets.RichLabel header_label;
|
|
|
|
|
|
|
|
[GtkChild]
|
|
|
|
public Widgets.Avatar avatar;
|
|
|
|
[GtkChild]
|
|
|
|
protected Widgets.RichLabel handle_label;
|
|
|
|
[GtkChild]
|
|
|
|
protected Label date_label;
|
|
|
|
[GtkChild]
|
|
|
|
protected Image pin_indicator;
|
|
|
|
[GtkChild]
|
|
|
|
public Revealer revealer;
|
|
|
|
[GtkChild]
|
|
|
|
protected Widgets.RichLabel content;
|
|
|
|
[GtkChild]
|
|
|
|
protected Widgets.RichLabel revealer_content;
|
|
|
|
[GtkChild]
|
|
|
|
protected Widgets.Attachment.Box attachments;
|
|
|
|
|
|
|
|
[GtkChild]
|
|
|
|
protected Box actions;
|
|
|
|
[GtkChild]
|
|
|
|
protected Button reply_button;
|
|
|
|
[GtkChild]
|
|
|
|
protected ToggleButton reblog_button;
|
|
|
|
[GtkChild]
|
|
|
|
protected Image reblog_icon;
|
|
|
|
[GtkChild]
|
|
|
|
protected ToggleButton favorite_button;
|
|
|
|
|
|
|
|
protected string escaped_spoiler {
|
|
|
|
owned get {
|
|
|
|
if (status.formal.has_spoiler) {
|
|
|
|
var text = Html.simplify (status.formal.spoiler_text ?? "");
|
|
|
|
var label = _("[ Toggle content ]");
|
|
|
|
text += @" <a href='tootle://toggle'>$label</a>";
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return Html.simplify (status.formal.content);
|
|
|
|
}
|
|
|
|
}
|
2018-04-14 12:09:06 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
protected string escaped_content {
|
|
|
|
owned get {
|
|
|
|
return status.formal.has_spoiler ? Html.simplify (status.formal.content) : "";
|
|
|
|
}
|
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
protected string handle {
|
|
|
|
owned get {
|
|
|
|
var name = Html.simplify (status.formal.account.display_name);
|
|
|
|
var handle = Html.simplify (status.formal.account.acct);
|
|
|
|
return @"<b>$name</b> @$handle";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected string date {
|
|
|
|
owned get {
|
|
|
|
var timeval = GLib.TimeVal ();
|
|
|
|
GLib.DateTime? date = null;
|
|
|
|
if (timeval.from_iso8601 (status.formal.created_at))
|
|
|
|
date = new GLib.DateTime.from_timeval_local (timeval);
|
|
|
|
|
|
|
|
return Granite.DateTime.get_relative_datetime (date);
|
|
|
|
}
|
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
construct {
|
2018-10-23 10:22:43 +00:00
|
|
|
button_press_event.connect (on_clicked);
|
2020-05-29 12:19:35 +00:00
|
|
|
content.activate_link.connect (on_toggle_spoiler);
|
|
|
|
notify["kind"].connect (on_kind_changed);
|
2018-04-14 12:09:06 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
if (kind == null) {
|
|
|
|
if (status.reblog != null)
|
|
|
|
kind = API.NotificationType.REBLOG_REMOTE_USER;
|
2018-04-21 09:21:03 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
status.formal.bind_property ("favorited", favorite_button, "active", BindingFlags.SYNC_CREATE);
|
|
|
|
favorite_button.clicked.connect (() => {
|
|
|
|
status.action (status.formal.favorited ? "unfavourite" : "favourite");
|
2018-04-18 09:13:22 +00:00
|
|
|
});
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
status.formal.bind_property ("reblogged", reblog_button, "active", BindingFlags.SYNC_CREATE);
|
|
|
|
reblog_button.clicked.connect (() => {
|
|
|
|
status.action (status.formal.reblogged ? "unreblog" : "reblog");
|
2018-05-16 11:23:48 +00:00
|
|
|
});
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
reply_button.clicked.connect (() => new Dialogs.Compose.reply (status));
|
|
|
|
|
|
|
|
bind_property ("escaped-spoiler", content, "label", BindingFlags.SYNC_CREATE);
|
|
|
|
bind_property ("escaped-content", revealer_content, "label", BindingFlags.SYNC_CREATE);
|
|
|
|
status.formal.account.bind_property ("avatar", avatar, "url", BindingFlags.SYNC_CREATE);
|
|
|
|
bind_property ("handle", handle_label, "label", BindingFlags.SYNC_CREATE);
|
|
|
|
bind_property ("date", date_label, "label", BindingFlags.SYNC_CREATE);
|
|
|
|
status.formal.bind_property ("pinned", pin_indicator, "visible", BindingFlags.SYNC_CREATE);
|
|
|
|
status.formal.bind_property ("replies-count", reply_button, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
|
|
|
|
target.set_string (((int64)src).to_string ());
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
status.formal.bind_property ("reblogs-count", reblog_button, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
|
|
|
|
target.set_string (((int64)src).to_string ());
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
status.bind_property ("favourites-count", favorite_button, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
|
|
|
|
target.set_string (((int64)src).to_string ());
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
status.formal.bind_property ("has_spoiler", revealer_content, "visible", BindingFlags.SYNC_CREATE);
|
|
|
|
revealer.reveal_child = !status.formal.has_spoiler;
|
|
|
|
|
|
|
|
if (status.formal.visibility == API.Visibility.DIRECT) {
|
|
|
|
reblog_icon.icon_name = status.formal.visibility.get_icon ();
|
|
|
|
reblog_button.sensitive = false;
|
|
|
|
reblog_button.tooltip_text = _("This post can't be boosted");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status.id <= 0) {
|
|
|
|
actions.destroy ();
|
|
|
|
date_label.destroy ();
|
|
|
|
content.single_line_mode = true;
|
|
|
|
content.lines = 2;
|
|
|
|
content.ellipsize = Pango.EllipsizeMode.END;
|
|
|
|
button_press_event.connect (on_avatar_clicked);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
button_press_event.connect (open);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!attachments.populate (status.formal.attachments) || status.id <= 0) {
|
|
|
|
attachments.destroy ();
|
|
|
|
}
|
2018-04-14 12:09:06 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
public Status (API.Status status, API.NotificationType? _kind = null) {
|
|
|
|
Object (status: status, kind: _kind);
|
2018-04-22 11:35:25 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
~Status () {
|
|
|
|
button_press_event.disconnect (on_clicked);
|
|
|
|
notify["kind"].disconnect (on_kind_changed);
|
2018-06-02 09:27:19 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
protected bool on_toggle_spoiler (string uri) {
|
|
|
|
if (uri == "tootle://toggle") {
|
|
|
|
revealer.reveal_child = !revealer.reveal_child;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2018-04-25 13:16:57 +00:00
|
|
|
}
|
2018-05-04 20:57:31 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
protected virtual void on_kind_changed () {
|
|
|
|
header_icon.visible = header_label.visible = (kind != null);
|
|
|
|
if (kind == null)
|
|
|
|
return;
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
header_icon.icon_name = kind.get_icon ();
|
|
|
|
header_label.label = kind.get_desc (status.account);
|
2018-05-02 12:00:43 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2019-03-11 12:28:51 +00:00
|
|
|
public bool on_avatar_clicked (EventButton ev) {
|
|
|
|
if (ev.button == 1) {
|
2020-05-29 12:19:35 +00:00
|
|
|
var view = new Views.Profile (status.formal.account);
|
2019-03-11 12:28:51 +00:00
|
|
|
return window.open_view (view);
|
|
|
|
}
|
|
|
|
return false;
|
2018-04-14 12:09:06 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-05-21 15:23:31 +00:00
|
|
|
public bool open (EventButton ev) {
|
2019-03-11 12:28:51 +00:00
|
|
|
if (ev.button == 1) {
|
2020-05-29 12:19:35 +00:00
|
|
|
var formal = status.formal;
|
2019-03-11 14:14:37 +00:00
|
|
|
var view = new Views.ExpandedStatus (formal);
|
2019-03-11 12:28:51 +00:00
|
|
|
return window.open_view (view);
|
|
|
|
}
|
|
|
|
return false;
|
2018-05-21 15:23:31 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2019-03-11 12:28:51 +00:00
|
|
|
protected virtual bool on_clicked (EventButton ev) {
|
2018-05-21 15:23:31 +00:00
|
|
|
if (ev.button == 3)
|
|
|
|
return open_menu (ev.button, ev.time);
|
2019-03-11 12:28:51 +00:00
|
|
|
return false;
|
2018-05-21 15:23:31 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-05-21 15:27:03 +00:00
|
|
|
public virtual bool open_menu (uint button, uint32 time) {
|
2018-05-21 15:23:31 +00:00
|
|
|
var menu = new Gtk.Menu ();
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-05-21 15:23:31 +00:00
|
|
|
var item_open_link = new Gtk.MenuItem.with_label (_("Open in Browser"));
|
2020-05-29 12:19:35 +00:00
|
|
|
item_open_link.activate.connect (() => Desktop.open_uri (status.formal.url));
|
2018-05-21 15:23:31 +00:00
|
|
|
var item_copy_link = new Gtk.MenuItem.with_label (_("Copy Link"));
|
2020-05-29 12:19:35 +00:00
|
|
|
item_copy_link.activate.connect (() => Desktop.copy (status.formal.url));
|
2018-05-21 15:23:31 +00:00
|
|
|
var item_copy = new Gtk.MenuItem.with_label (_("Copy Text"));
|
|
|
|
item_copy.activate.connect (() => {
|
2020-05-29 12:19:35 +00:00
|
|
|
var sanitized = Html.remove_tags (status.formal.content);
|
2018-05-30 19:49:16 +00:00
|
|
|
Desktop.copy (sanitized);
|
2018-05-21 15:23:31 +00:00
|
|
|
});
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2019-03-14 11:55:27 +00:00
|
|
|
if (status.is_owned ()) {
|
2020-05-29 12:19:35 +00:00
|
|
|
var item_pin = new Gtk.MenuItem.with_label (status.pinned ? _("Unpin from Profile") : _("Pin on Profile"));
|
|
|
|
item_pin.activate.connect (() => {
|
|
|
|
status.action (status.formal.pinned ? "unpin" : "pin");
|
|
|
|
});
|
2018-10-24 09:00:40 +00:00
|
|
|
menu.add (item_pin);
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-10-24 12:01:32 +00:00
|
|
|
var item_delete = new Gtk.MenuItem.with_label (_("Delete"));
|
|
|
|
item_delete.activate.connect (() => status.poof ());
|
2018-05-22 12:47:25 +00:00
|
|
|
menu.add (item_delete);
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-10-24 12:01:32 +00:00
|
|
|
var item_redraft = new Gtk.MenuItem.with_label (_("Redraft"));
|
2020-05-29 12:19:35 +00:00
|
|
|
item_redraft.activate.connect (() => new Dialogs.Compose.redraft (status.formal));
|
2018-10-24 12:01:32 +00:00
|
|
|
menu.add (item_redraft);
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2019-03-11 14:14:37 +00:00
|
|
|
menu.add (new SeparatorMenuItem ());
|
2018-05-22 12:47:25 +00:00
|
|
|
}
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2020-05-29 12:19:35 +00:00
|
|
|
// if (is_notification) {
|
|
|
|
// var item_muting = new Gtk.MenuItem.with_label (status.muted ? _("Unmute Conversation") : _("Mute Conversation"));
|
|
|
|
// item_muting.activate.connect (() => status.update_muted (!is_muted) );
|
|
|
|
// menu.add (item_muting);
|
|
|
|
// }
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-05-21 15:27:03 +00:00
|
|
|
menu.add (item_open_link);
|
2019-03-11 14:14:37 +00:00
|
|
|
menu.add (new SeparatorMenuItem ());
|
2018-05-21 15:27:03 +00:00
|
|
|
menu.add (item_copy_link);
|
|
|
|
menu.add (item_copy);
|
2019-03-07 16:16:52 +00:00
|
|
|
|
2018-05-21 15:23:31 +00:00
|
|
|
menu.show_all ();
|
|
|
|
menu.attach_widget = this;
|
2018-10-23 10:54:32 +00:00
|
|
|
menu.popup_at_pointer ();
|
2018-05-21 15:23:31 +00:00
|
|
|
return true;
|
2018-04-26 14:05:03 +00:00
|
|
|
}
|
2018-04-14 12:09:06 +00:00
|
|
|
|
|
|
|
}
|