Tooth/src/Widgets/Status.vala

395 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
2022-11-13 20:57:43 +00:00
[GtkTemplate (ui = "/dev/geopjr/tooth/ui/widgets/status.ui")]
public class Tooth.Widgets.Status : ListBoxRow {
2019-03-07 16:16:52 +00:00
2021-07-23 11:41:03 +00:00
API.Status? _bound_status = null;
public API.Status? status {
get { return _bound_status; }
set {
if (_bound_status != null)
warning ("Trying to rebind a Status widget! This is not supposed to happen!");
_bound_status = value;
if (_bound_status != null)
bind ();
}
}
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
public API.Account? kind_instigator { get; set; default = null; }
2020-10-24 10:54:37 +00:00
2021-07-23 11:41:03 +00:00
string? _kind = null;
public string? kind {
get { return _kind; }
set {
_kind = value;
change_kind ();
}
}
2020-10-24 10:54:37 +00:00
2021-07-23 11:41:03 +00:00
[GtkChild] protected unowned Grid grid;
[GtkChild] protected unowned Image header_icon;
2022-11-17 18:32:26 +00:00
[GtkChild] protected unowned Widgets.RichLabelContainer header_label;
2021-07-23 11:41:03 +00:00
[GtkChild] public unowned Image thread_line;
[GtkChild] public unowned Widgets.Avatar avatar;
2022-11-17 18:32:26 +00:00
[GtkChild] protected unowned Widgets.RichLabelContainer name_label;
2021-07-23 11:41:03 +00:00
[GtkChild] protected unowned Label handle_label;
[GtkChild] protected unowned Box indicators;
[GtkChild] protected unowned Label date_label;
[GtkChild] protected unowned Image pin_indicator;
[GtkChild] protected unowned Image indicator;
[GtkChild] protected unowned Box content_column;
[GtkChild] protected unowned Stack spoiler_stack;
[GtkChild] protected unowned Box content_box;
[GtkChild] protected unowned Widgets.MarkupView content;
[GtkChild] protected unowned Widgets.Attachment.Box attachments;
[GtkChild] protected unowned Button spoiler_button;
[GtkChild] protected unowned Widgets.RichLabel spoiler_label;
[GtkChild] protected unowned Label spoiler_label_rev;
[GtkChild] protected unowned Box spoiler_status_con;
2021-07-23 11:41:03 +00:00
2022-11-27 01:32:16 +00:00
[GtkChild] protected unowned Box status_stats;
[GtkChild] protected unowned Label reblog_count_label;
[GtkChild] protected unowned Label fav_count_label;
[GtkChild] public unowned Box actions;
2021-07-23 11:41:03 +00:00
[GtkChild] public unowned Widgets.VoteBox poll;
2021-07-23 11:41:03 +00:00
protected Button reply_button;
protected Adw.ButtonContent reply_button_content;
2021-07-23 11:41:03 +00:00
protected StatusActionButton reblog_button;
protected StatusActionButton favorite_button;
protected StatusActionButton bookmark_button;
2022-11-27 01:32:16 +00:00
public bool is_conversation_open { get; set; default = false; }
2021-07-23 11:41:03 +00:00
construct {
open.connect (on_open);
rebuild_actions ();
2020-10-24 10:54:37 +00:00
}
2021-07-23 11:41:03 +00:00
public Status (API.Status status) {
Object (
kind_instigator: status.account,
status: status
);
2020-10-24 10:54:37 +00:00
2021-07-23 11:41:03 +00:00
if (kind == null && status.reblog != null) {
kind = Mastodon.Account.KIND_REMOTE_REBLOG;
}
check_actions();
2021-07-23 11:41:03 +00:00
}
~Status () {
message ("Destroying Status widget");
}
2020-07-30 19:02:03 +00:00
private void check_actions() {
if (kind == Mastodon.Account.KIND_FOLLOW || kind == Mastodon.Account.KIND_FOLLOW_REQUEST) {
actions.visible = false;
}
}
protected string spoiler_text {
2020-07-30 19:02:03 +00:00
owned get {
var text = status.formal.spoiler_text;
if (text == null || text == "") {
return _("Show More");
} else {
spoiler_text_revealed = text;
return text;
}
2020-07-30 19:02:03 +00:00
}
}
public string spoiler_text_revealed { get; set; default = _("Sensitive"); }
2021-07-23 11:41:03 +00:00
public bool reveal_spoiler { get; set; default = true; }
2020-07-30 19:02:03 +00:00
2020-08-01 21:47:22 +00:00
protected string date {
owned get {
return DateTime.humanize (status.formal.created_at);
2020-08-01 21:47:22 +00:00
}
}
public string title_text {
2020-05-29 12:19:35 +00:00
owned get {
return status.formal.account.display_name;
2020-05-29 12:19:35 +00:00
}
}
2020-08-01 21:47:22 +00:00
public string subtitle_text {
2020-05-29 12:19:35 +00:00
owned get {
return status.formal.account.handle;
2020-07-12 08:27:11 +00:00
}
}
2020-08-01 21:47:22 +00:00
public string? avatar_url {
2020-07-12 08:27:11 +00:00
owned get {
2020-08-01 21:47:22 +00:00
return status.formal.account.avatar;
2020-05-29 12:19:35 +00:00
}
}
2019-03-07 16:16:52 +00:00
2020-08-01 21:47:22 +00:00
public signal void open ();
public virtual void on_open () {
2020-07-31 23:42:14 +00:00
if (status.id == "")
on_avatar_clicked ();
2020-08-01 15:40:56 +00:00
else
status.open ();
2020-07-30 19:02:03 +00:00
}
2021-07-23 11:41:03 +00:00
protected virtual void change_kind () {
string icon = null;
string descr = null;
2022-11-17 18:32:26 +00:00
string label_url = null;
check_actions();
2022-11-17 18:32:26 +00:00
accounts.active.describe_kind (this.kind, out icon, out descr, this.kind_instigator, out label_url);
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
header_icon.visible = header_label.visible = (icon != null);
if (icon == null) return;
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
header_icon.icon_name = icon;
2022-11-17 18:32:26 +00:00
header_label.set_label(descr, label_url, this.kind_instigator.emojis_map);
2021-07-23 11:41:03 +00:00
}
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
protected virtual void bind () {
// Content
bind_property ("spoiler-text", spoiler_label, "label", BindingFlags.SYNC_CREATE);
bind_property ("spoiler-text-revealed", spoiler_label_rev, "label", BindingFlags.SYNC_CREATE);
status.formal.bind_property ("content", content, "content", BindingFlags.SYNC_CREATE);
2022-11-27 01:32:16 +00:00
bind_property ("is_conversation_open", status_stats, "visible", BindingFlags.SYNC_CREATE);
status.formal.bind_property ("reblogs_count", reblog_count_label, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
int64 srcval = (int64) src;
target.set_string (@"<b>$srcval</b> " + _("Reblogs"));
return true;
});
status.formal.bind_property ("favourites_count", fav_count_label, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
int64 srcval = (int64) src;
target.set_string (@"<b>$srcval</b> " + _("Favourites"));
return true;
});
status.formal.bind_property ("replies_count", reply_button_content, "label", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
int64 srcval = (int64) src;
if (srcval > 0) {
reply_button_content.margin_start = 6;
reply_button_content.margin_end = 6;
} else {
reply_button_content.margin_start = 0;
reply_button_content.margin_end = 0;
}
if (srcval == 1)
target.set_string (@"1");
else if (srcval > 1)
2022-12-02 23:24:28 +00:00
target.set_string (@"1+");
else
target.set_string("");
return true;
});
2022-11-17 18:32:26 +00:00
// bind_property ("title_text", name_label, "label", BindingFlags.SYNC_CREATE);
// title_text
2022-11-17 20:35:01 +00:00
name_label.set_label(title_text, status.formal.account.handle, status.formal.account.emojis_map, true);
bind_property ("subtitle_text", handle_label, "label", BindingFlags.SYNC_CREATE);
2020-05-29 12:19:35 +00:00
bind_property ("date", date_label, "label", BindingFlags.SYNC_CREATE);
status.formal.bind_property ("pinned", pin_indicator, "visible", BindingFlags.SYNC_CREATE);
2022-12-02 16:15:24 +00:00
status.formal.bind_property ("visibility", indicator, "icon_name", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
target.set_string (accounts.active.visibility[src.get_string ()].icon_name);
return true;
});
2020-10-18 20:35:59 +00:00
status.formal.bind_property ("account", avatar, "account", BindingFlags.SYNC_CREATE);
2020-05-29 12:19:35 +00:00
2021-07-23 11:41:03 +00:00
// Spoiler //TODO: Spoilers
// reveal_spoiler = true;
// spoiler_stack.visible_child_name = "content";
// status.formal.bind_property ("has-spoiler", this, "reveal-spoiler", BindingFlags.INVERT_BOOLEAN);
status.formal.bind_property ("has-spoiler", this, "reveal-spoiler", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
target.set_boolean (!src.get_boolean () || settings.show_spoilers);
return true;
});
bind_property ("reveal-spoiler", spoiler_stack, "visible-child-name", BindingFlags.SYNC_CREATE, (b, src, ref target) => {
var name = reveal_spoiler ? "content" : "spoiler";
spoiler_status_con.visible = src.get_boolean() && status.formal.has_spoiler;
target.set_string (name);
return true;
});
2021-07-23 11:41:03 +00:00
// Actions
reblog_button.bind (status.formal);
favorite_button.bind (status.formal);
bookmark_button.bind (status.formal);
reply_button.set_child(reply_button_content);
reply_button.add_css_class("ttl-status-action-reply");
reply_button.tooltip_text = _("Reply");
2021-07-23 11:41:03 +00:00
if (status.formal.in_reply_to_id != null)
reply_button_content.icon_name = "tooth-reply-all-symbolic";
2021-07-23 11:41:03 +00:00
else
reply_button_content.icon_name = "tooth-reply-sender-symbolic";
2021-07-23 11:41:03 +00:00
if (!status.can_be_boosted) {
2020-07-30 19:02:03 +00:00
reblog_button.sensitive = false;
reblog_button.tooltip_text = _("This post can't be boosted");
2021-07-23 11:41:03 +00:00
reblog_button.icon_name = accounts.active.visibility[status.visibility].icon_name;
}
else {
reblog_button.sensitive = true;
reblog_button.tooltip_text = _("Boost");
reblog_button.icon_name = "tooth-media-playlist-repeat-symbolic";
2020-07-30 19:02:03 +00:00
}
if (status.id == "") {
actions.destroy ();
date_label.destroy ();
}
if (status.poll==null){
poll.hide();
}
else{
poll.status_parent=status;
status.bind_property ("poll", poll, "poll", BindingFlags.SYNC_CREATE);
}
2021-07-23 11:41:03 +00:00
// Attachments
attachments.list = status.formal.media_attachments;
2020-07-30 19:02:03 +00:00
}
2021-07-23 11:41:03 +00:00
protected virtual void append_actions () {
reply_button = new Button ();
reply_button_content = new Adw.ButtonContent ();
2021-07-23 11:41:03 +00:00
reply_button.clicked.connect (() => new Dialogs.Compose.reply (status));
actions.append (reply_button);
reblog_button = new StatusActionButton () {
prop_name = "reblogged",
action_on = "reblog",
action_off = "unreblog"
};
reblog_button.add_css_class("ttl-status-action-reblog");
reblog_button.tooltip_text = _("Boost");
2021-07-23 11:41:03 +00:00
actions.append (reblog_button);
favorite_button = new StatusActionButton () {
prop_name = "favourited",
action_on = "favourite",
action_off = "unfavourite",
icon_name = "tooth-unstarred-symbolic",
icon_toggled_name = "tooth-starred-symbolic"
2021-07-23 11:41:03 +00:00
};
favorite_button.add_css_class("ttl-status-action-star");
favorite_button.tooltip_text = _("Favourite");
2021-07-23 11:41:03 +00:00
actions.append (favorite_button);
bookmark_button = new StatusActionButton () {
prop_name = "bookmarked",
action_on = "bookmark",
action_off = "unbookmark",
icon_name = "tooth-bookmarks-symbolic",
icon_toggled_name = "tooth-bookmarks-filled-symbolic"
2021-07-23 11:41:03 +00:00
};
bookmark_button.add_css_class("ttl-status-action-bookmark");
bookmark_button.tooltip_text = _("Bookmark");
2021-07-23 11:41:03 +00:00
actions.append (bookmark_button);
2020-07-30 19:02:03 +00:00
}
2021-07-23 11:41:03 +00:00
void rebuild_actions () {
for (var w = actions.get_first_child (); w != null; w = w.get_next_sibling ())
actions.remove (w);
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
append_actions ();
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
// var menu_button = new MenuButton (); //TODO: Status menu
// menu_button.icon_name = "tooth-view-more-symbolic";
2021-07-23 11:41:03 +00:00
// menu_button.get_first_child ().add_css_class ("flat");
// actions.append (menu_button);
2020-07-30 19:02:03 +00:00
for (var w = actions.get_first_child (); w != null; w = w.get_next_sibling ()) {
2021-07-23 11:41:03 +00:00
w.add_css_class ("flat");
w.add_css_class ("circular");
w.halign = Align.CENTER;
}
2020-07-30 19:02:03 +00:00
}
2021-07-23 11:41:03 +00:00
[GtkCallback] public void toggle_spoiler () {
reveal_spoiler = !reveal_spoiler;
}
2020-07-30 19:02:03 +00:00
2021-07-23 11:41:03 +00:00
[GtkCallback] public void on_avatar_clicked () {
status.formal.account.open ();
2020-07-30 19:02:03 +00:00
}
2018-04-14 12:09:06 +00:00
public void expand_root () {
activatable = false;
content.selectable = true;
content.get_style_context ().add_class ("ttl-large-body");
2021-07-23 11:41:03 +00:00
var mgr = (content_column.get_parent () as Grid).get_layout_manager ();
var child = mgr.get_layout_child (content_column);
child.set_property ("column", 0);
child.set_property ("column_span", 2);
}
// Threads
public enum ThreadRole {
NONE,
START,
MIDDLE,
END;
public static void connect_posts (Widgets.Status? prev, Widgets.Status curr) {
if (prev == null) {
curr.thread_role = NONE;
return;
}
switch (prev.thread_role) {
case NONE:
prev.thread_role = START;
curr.thread_role = END;
break;
case END:
prev.thread_role = MIDDLE;
curr.thread_role = END;
break;
}
}
}
2021-07-23 11:41:03 +00:00
public ThreadRole thread_role { get; set; default = ThreadRole.NONE; }
2020-10-24 10:54:37 +00:00
public void install_thread_line () {
var l = thread_line;
switch (thread_role) {
case NONE:
l.visible = false;
break;
case START:
l.valign = Align.FILL;
l.margin_top = 24;
l.visible = true;
break;
case MIDDLE:
l.valign = Align.FILL;
l.margin_top = 0;
l.visible = true;
break;
case END:
l.valign = Align.START;
l.margin_top = 0;
l.visible = true;
break;
}
}
2018-04-14 12:09:06 +00:00
}