Tooth/src/Widgets/Status.vala

319 lines
11 KiB
Vala
Raw Normal View History

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
using Granite;
2019-03-11 14:14:37 +00:00
public class Tootle.Widgets.Status : EventBox {
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
public API.Status status;
2018-05-22 13:18:39 +00:00
public bool is_notification = false;
public const int AVATAR_SIZE = 32;
2019-03-07 16:16:52 +00:00
2018-10-24 10:50:40 +00:00
public Separator? separator;
2018-04-14 12:09:06 +00:00
public Granite.Widgets.Avatar avatar;
2018-10-24 10:50:40 +00:00
protected Grid grid;
2019-03-11 14:14:37 +00:00
protected Widgets.RichLabel title_user;
2018-10-24 10:50:40 +00:00
protected Label title_date;
protected Label title_acct;
2019-03-12 08:12:53 +00:00
public Revealer revealer;
2019-03-11 14:14:37 +00:00
protected Widgets.RichLabel content_label;
protected Widgets.RichLabel? content_spoiler;
2018-10-24 10:50:40 +00:00
protected Button? spoiler_button;
protected Box title_box;
2019-03-07 16:16:52 +00:00
protected Widgets.AttachmentGrid attachments;
2018-10-24 10:50:40 +00:00
protected Image pin_indicator;
2019-03-07 16:16:52 +00:00
2018-10-24 10:50:40 +00:00
protected Box counters;
protected Label replies;
protected Label reblogs;
protected Label favorites;
2019-03-11 14:14:37 +00:00
protected Widgets.ImageToggleButton reblog;
protected Widgets.ImageToggleButton favorite;
protected Widgets.ImageToggleButton reply;
2018-04-14 12:09:06 +00:00
construct {
2018-10-24 10:50:40 +00:00
grid = new Grid ();
2019-03-07 16:16:52 +00:00
avatar = new Granite.Widgets.Avatar.with_default_icon (AVATAR_SIZE);
2018-10-24 10:50:40 +00:00
avatar.valign = Align.START;
2018-05-01 16:37:45 +00:00
avatar.margin_top = 6;
avatar.margin_start = 6;
2018-04-14 12:09:06 +00:00
avatar.margin_end = 6;
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
title_box = new Box (Orientation.HORIZONTAL, 6);
title_box.hexpand = true;
title_box.margin_end = 12;
title_box.margin_top = 6;
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
title_user = new Widgets.RichLabel ("");
title_box.pack_start (title_user, false, false, 0);
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
title_acct = new Label ("");
title_acct.opacity = 0.5;
2018-05-04 21:33:52 +00:00
title_acct.ellipsize = Pango.EllipsizeMode.END;
title_box.pack_start (title_acct, false, false, 0);
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
title_date = new Label ("");
title_date.opacity = 0.5;
title_date.ellipsize = Pango.EllipsizeMode.END;
title_box.pack_end (title_date, false, false, 0);
title_box.show_all ();
2019-03-07 16:16:52 +00:00
2018-10-24 09:29:36 +00:00
pin_indicator = new Image.from_icon_name ("view-pin-symbolic", IconSize.MENU);
pin_indicator.opacity = 0.5;
title_box.pack_end (pin_indicator, false, false, 0);
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
content_label = new Widgets.RichLabel ("");
2018-05-04 20:57:31 +00:00
content_label.wrap_words ();
2019-03-07 16:16:52 +00:00
attachments = new Widgets.AttachmentGrid ();
2018-10-24 10:50:40 +00:00
var revealer_box = new Box (Orientation.VERTICAL, 6);
revealer_box.margin_end = 12;
2018-10-24 10:50:40 +00:00
revealer_box.add (content_label);
revealer_box.add (attachments);
revealer = new Revealer ();
revealer.reveal_child = true;
revealer.add (revealer_box);
2019-03-07 16:16:52 +00:00
2018-10-24 10:50:40 +00:00
reblogs = new Label ("0");
favorites = new Label ("0");
replies = new Label ("0");
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
reblog = new Widgets.ImageToggleButton ("media-playlist-repeat-symbolic");
2018-05-11 11:28:49 +00:00
reblog.set_action ();
2018-04-30 16:04:22 +00:00
reblog.tooltip_text = _("Boost");
2018-04-16 18:22:42 +00:00
reblog.toggled.connect (() => {
if (reblog.sensitive)
2019-03-14 11:55:27 +00:00
status.get_formal ().set_reblogged (reblog.get_active ());
2018-04-16 18:22:42 +00:00
});
2019-03-11 14:14:37 +00:00
favorite = new Widgets.ImageToggleButton ("emblem-favorite-symbolic");
2018-05-11 11:28:49 +00:00
favorite.set_action ();
2018-04-30 16:04:22 +00:00
favorite.tooltip_text = _("Favorite");
2018-04-16 18:22:42 +00:00
favorite.toggled.connect (() => {
if (favorite.sensitive)
2019-03-14 11:55:27 +00:00
status.get_formal ().set_favorited (favorite.get_active ());
2018-04-16 18:22:42 +00:00
});
2019-03-11 14:14:37 +00:00
reply = new Widgets.ImageToggleButton ("mail-replied-symbolic");
2018-05-11 11:28:49 +00:00
reply.set_action ();
2018-04-30 16:04:22 +00:00
reply.tooltip_text = _("Reply");
2018-04-24 14:50:38 +00:00
reply.toggled.connect (() => {
reply.set_active (false);
2019-03-11 14:14:37 +00:00
Dialogs.Compose.reply (status.get_formal ());
2018-04-24 14:50:38 +00:00
});
2019-03-07 16:16:52 +00:00
2018-10-24 10:50:40 +00:00
counters = new Box (Orientation.HORIZONTAL, 6);
2018-04-14 12:09:06 +00:00
counters.margin_top = 6;
2018-05-01 16:37:45 +00:00
counters.margin_bottom = 6;
2018-04-24 10:11:10 +00:00
counters.add (reblog);
counters.add (reblogs);
counters.add (favorite);
counters.add (favorites);
2018-04-24 14:50:38 +00:00
counters.add (reply);
2018-10-24 10:50:40 +00:00
counters.add (replies);
2018-04-14 12:09:06 +00:00
counters.show_all ();
2019-03-07 16:16:52 +00:00
2018-05-18 21:14:12 +00:00
add (grid);
2018-04-25 11:45:50 +00:00
grid.attach (avatar, 1, 1, 1, 4);
grid.attach (title_box, 2, 2, 1, 1);
2018-04-25 11:45:50 +00:00
grid.attach (revealer, 2, 4, 1, 1);
grid.attach (counters, 2, 5, 1, 1);
2018-05-04 20:57:31 +00:00
show_all ();
2019-03-07 16:16:52 +00:00
2018-10-23 10:22:43 +00:00
button_press_event.connect (on_clicked);
2018-04-14 12:09:06 +00:00
}
2019-03-11 14:14:37 +00:00
public Status (API.Status status, bool notification = false) {
2018-04-16 18:22:42 +00:00
this.status = status;
2018-05-18 21:14:12 +00:00
this.status.updated.connect (rebind);
2019-03-07 16:16:52 +00:00
is_notification = notification;
if (status.reblog != null) {
2018-10-24 10:50:40 +00:00
var image = new Image.from_icon_name("media-playlist-repeat-symbolic", IconSize.BUTTON);
image.halign = Align.END;
2018-05-01 16:37:45 +00:00
image.margin_end = 6;
image.margin_top = 6;
2018-04-21 09:21:03 +00:00
image.show ();
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
var label_text = API.NotificationType.REBLOG_REMOTE_USER.get_desc (status.account);
var label = new Widgets.RichLabel (label_text);
2018-10-24 10:50:40 +00:00
label.halign = Align.START;
2018-05-01 16:37:45 +00:00
label.margin_top = 6;
2018-04-21 09:21:03 +00:00
label.show ();
2019-03-07 16:16:52 +00:00
2018-04-25 11:45:50 +00:00
grid.attach (image, 1, 0, 1, 1);
grid.attach (label, 2, 0, 2, 1);
2018-04-21 09:21:03 +00:00
}
2019-03-07 16:16:52 +00:00
2019-03-12 08:12:53 +00:00
if (status.has_spoiler ()) {
2018-04-23 17:02:21 +00:00
revealer.reveal_child = false;
2018-10-24 10:50:40 +00:00
var spoiler_box = new Box (Orientation.HORIZONTAL, 6);
2018-05-04 20:57:31 +00:00
spoiler_box.margin_end = 12;
2019-03-07 16:16:52 +00:00
2018-05-04 20:57:31 +00:00
var spoiler_button_text = _("Toggle content");
if (status.sensitive && status.attachments != null) {
2019-03-11 14:14:37 +00:00
spoiler_button = new Button.from_icon_name ("mail-attachment-symbolic", IconSize.BUTTON);
2018-05-04 20:57:31 +00:00
spoiler_button.label = spoiler_button_text;
spoiler_button.always_show_image = true;
content_label.margin_top = 6;
}
else {
spoiler_button = new Button.with_label (spoiler_button_text);
}
2018-06-01 17:08:00 +00:00
spoiler_button.hexpand = true;
2018-10-24 10:50:40 +00:00
spoiler_button.halign = Align.END;
2018-04-23 17:02:21 +00:00
spoiler_button.clicked.connect (() => revealer.set_reveal_child (!revealer.child_revealed));
2019-03-07 16:16:52 +00:00
2018-05-04 20:57:31 +00:00
var spoiler_text = _("[ This post contains sensitive content ]");
if (status.spoiler_text != null)
spoiler_text = status.spoiler_text;
2019-03-11 14:14:37 +00:00
content_spoiler = new Widgets.RichLabel (spoiler_text);
2018-05-04 20:57:31 +00:00
content_spoiler.wrap_words ();
2019-03-07 16:16:52 +00:00
2018-05-04 20:57:31 +00:00
spoiler_box.add (content_spoiler);
spoiler_box.add (spoiler_button);
spoiler_box.show_all ();
2018-04-25 11:45:50 +00:00
grid.attach (spoiler_box, 2, 3, 1, 1);
2018-04-23 16:43:29 +00:00
}
2019-03-07 16:16:52 +00:00
if (!is_notification && status.get_formal ().attachments != null)
attachments.pack (status.get_formal ().attachments);
2018-05-09 14:20:40 +00:00
else
attachments.destroy ();
2019-03-07 16:16:52 +00:00
2018-04-18 09:13:22 +00:00
destroy.connect (() => {
avatar.show_default (AVATAR_SIZE);
2018-10-24 10:50:40 +00:00
if (separator != null)
2018-04-18 09:13:22 +00:00
separator.destroy ();
});
2019-03-07 16:16:52 +00:00
2018-06-06 14:19:11 +00:00
network.status_removed.connect (id => {
2018-10-24 12:01:32 +00:00
if (id == status.id)
2018-05-16 11:23:48 +00:00
destroy ();
});
2019-03-07 16:16:52 +00:00
2018-05-01 13:53:46 +00:00
rebind ();
2018-04-14 12:09:06 +00:00
}
2019-03-07 16:16:52 +00:00
2018-05-05 15:38:01 +00:00
public void highlight () {
2018-05-01 16:37:45 +00:00
grid.get_style_context ().add_class ("card");
grid.margin_bottom = 6;
2018-04-22 11:35:25 +00:00
}
2019-03-07 16:16:52 +00:00
public int get_avatar_size () {
return AVATAR_SIZE * get_style_context ().get_scale ();
}
2019-03-07 16:16:52 +00:00
2018-05-05 15:38:01 +00:00
public void rebind () {
var formal = status.get_formal ();
2019-03-07 16:16:52 +00:00
2018-06-06 14:19:11 +00:00
title_user.set_label ("<b>%s</b>".printf ((formal.account.display_name)));
title_acct.label = "@" + formal.account.acct;
content_label.set_label (formal.content);
content_label.mentions = formal.mentions;
2018-10-24 09:29:36 +00:00
pin_indicator.visible = status.pinned;
2019-03-07 16:16:52 +00:00
var datetime = parse_date_iso8601 (formal.created_at);
title_date.label = Granite.DateTime.get_relative_datetime (datetime);
2019-03-07 16:16:52 +00:00
reblogs.label = formal.reblogs_count.to_string ();
favorites.label = formal.favourites_count.to_string ();
2018-10-24 10:50:40 +00:00
replies.label = formal.replies_count.to_string ();
2019-03-07 16:16:52 +00:00
2018-04-30 16:04:22 +00:00
reblog.sensitive = false;
reblog.active = formal.reblogged;
2018-04-16 18:22:42 +00:00
reblog.sensitive = true;
2018-04-30 16:04:22 +00:00
favorite.sensitive = false;
favorite.active = formal.favorited;
2018-04-16 18:22:42 +00:00
favorite.sensitive = true;
2019-03-07 16:16:52 +00:00
2019-03-11 14:14:37 +00:00
if (formal.visibility == API.StatusVisibility.DIRECT) {
2018-05-11 11:28:49 +00:00
reblog.sensitive = false;
reblog.icon.icon_name = formal.visibility.get_icon ();
2018-05-11 11:28:49 +00:00
reblog.tooltip_text = _("This post can't be boosted");
}
2019-03-07 16:16:52 +00:00
2018-06-06 14:19:11 +00:00
network.load_avatar (formal.account.avatar, avatar, get_avatar_size ());
2018-04-25 13:16:57 +00:00
}
2018-05-04 20:57:31 +00:00
private GLib.DateTime? parse_date_iso8601 (string date) {
2018-05-21 10:40:49 +00:00
var timeval = GLib.TimeVal ();
if (timeval.from_iso8601 (date))
return new GLib.DateTime.from_timeval_local (timeval);
2019-03-07 16:16:52 +00:00
return null;
}
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) {
2019-03-11 14:14:37 +00:00
var view = new Views.Profile (status.get_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) {
var formal = status.get_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-22 13:18:39 +00:00
var is_muted = status.muted;
var is_pinned = status.pinned;
2019-03-07 16:16:52 +00:00
2018-05-22 13:18:39 +00:00
var item_muting = new Gtk.MenuItem.with_label (is_muted ? _("Unmute Conversation") : _("Mute Conversation"));
item_muting.activate.connect (() => status.set_muted (!is_muted));
2018-05-21 15:23:31 +00:00
var item_open_link = new Gtk.MenuItem.with_label (_("Open in Browser"));
2018-07-08 00:47:35 +00:00
item_open_link.activate.connect (() => Desktop.open_uri (status.get_formal ().url));
2018-05-21 15:23:31 +00:00
var item_copy_link = new Gtk.MenuItem.with_label (_("Copy Link"));
2018-07-08 00:47:35 +00:00
item_copy_link.activate.connect (() => Desktop.copy (status.get_formal ().url));
2018-05-21 15:23:31 +00:00
var item_copy = new Gtk.MenuItem.with_label (_("Copy Text"));
item_copy.activate.connect (() => {
2018-07-08 00:47:35 +00:00
var sanitized = Html.remove_tags (status.get_formal ().content);
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 ()) {
2018-10-24 12:01:32 +00:00
var item_pin = new Gtk.MenuItem.with_label (is_pinned ? _("Unpin from Profile") : _("Pin on Profile"));
item_pin.activate.connect (() => status.set_pinned (!is_pinned));
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"));
2019-03-11 14:14:37 +00:00
item_redraft.activate.connect (() => Dialogs.Compose.redraft (status.get_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
2019-03-14 11:55:27 +00:00
if (is_notification)
2018-05-22 13:18:39 +00:00
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
}