tootle-linux-client/src/Dialogs/Compose.vala

242 lines
8.4 KiB
Vala
Raw Normal View History

2018-04-14 14:09:06 +02:00
using Gtk;
2019-03-11 15:14:37 +01:00
public class Tootle.Dialogs.Compose : Dialog {
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
private static Compose dialog;
2019-03-07 17:16:52 +01:00
2018-10-23 12:05:24 +02:00
protected TextView text;
private ScrolledWindow scroll;
private Label counter;
2019-03-11 15:14:37 +01:00
private Widgets.ImageToggleButton spoiler;
2018-10-23 12:05:24 +02:00
private MenuButton visibility;
private Button attach;
private Button cancel;
private Button publish;
2019-03-07 17:16:52 +01:00
protected Widgets.AttachmentGrid attachments;
2018-10-23 12:05:24 +02:00
private Revealer spoiler_revealer;
private Entry spoiler_text;
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
protected API.Status? replying_to;
protected API.Status? redrafting;
protected API.StatusVisibility visibility_opt = API.StatusVisibility.PUBLIC;
protected int char_limit;
2018-04-14 14:09:06 +02:00
2019-03-11 15:14:37 +01:00
public Compose (API.Status? _replying_to = null, API.Status? _redrafting = null) {
2018-10-23 12:05:24 +02:00
border_width = 6;
deletable = false;
resizable = true;
title = _("Toot");
transient_for = window;
char_limit = settings.char_limit;
2018-10-24 14:01:32 +02:00
replying_to = _replying_to;
redrafting = _redrafting;
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
if (replying_to != null)
visibility_opt = replying_to.visibility;
if (redrafting != null)
visibility_opt = redrafting.visibility;
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
var actions = get_action_area ().get_parent () as Box;
2018-04-15 13:29:55 +02:00
var content = get_content_area ();
2018-05-09 16:20:40 +02:00
get_action_area ().hexpand = false;
2019-03-07 17:16:52 +01:00
2018-04-15 13:29:55 +02:00
visibility = get_visibility_btn ();
2018-05-09 16:20:40 +02:00
visibility.tooltip_text = _("Post Visibility");
visibility.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT);
visibility.get_style_context ().remove_class ("image-button");
2018-05-09 16:20:40 +02:00
visibility.can_default = false;
2018-10-24 14:01:32 +02:00
(visibility as Widget).set_focus_on_click (false);
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
attach = new Button.from_icon_name ("mail-attachment-symbolic");
2018-05-09 16:20:40 +02:00
attach.tooltip_text = _("Add Media");
2019-03-11 15:14:37 +01:00
attach.valign = Align.CENTER;
2018-05-09 16:20:40 +02:00
attach.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT);
attach.get_style_context ().remove_class ("image-button");
attach.can_default = false;
2018-10-24 14:01:32 +02:00
(attach as Widget).set_focus_on_click (false);
2018-05-09 16:20:40 +02:00
attach.clicked.connect (() => attachments.select ());
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
spoiler = new Widgets.ImageToggleButton ("image-red-eye-symbolic");
2018-05-19 19:32:19 +02:00
spoiler.tooltip_text = _("Spoiler Warning");
spoiler.set_action ();
spoiler.toggled.connect (() => {
spoiler_revealer.reveal_child = spoiler.active;
validate ();
});
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
cancel = add_button (_("Cancel"), 5) as Button;
cancel.clicked.connect(() => destroy ());
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
if (redrafting != null) {
publish = add_button (_("Redraft"), 5) as Button;
publish.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
publish.clicked.connect (redraft_post);
}
else {
publish = add_button (_("Toot!"), 5) as Button;
publish.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
publish.clicked.connect (publish_post);
}
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
spoiler_text = new Entry ();
spoiler_text.margin_start = 6;
spoiler_text.margin_end = 6;
spoiler_text.placeholder_text = _("Write your warning here");
2018-06-01 15:10:47 +02:00
spoiler_text.changed.connect (validate);
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
spoiler_revealer = new Revealer ();
spoiler_revealer.add (spoiler_text);
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
text = new TextView ();
2018-04-14 14:09:06 +02:00
text.get_style_context ().add_class ("toot-text");
2019-03-11 15:14:37 +01:00
text.wrap_mode = WrapMode.WORD;
text.accepts_tab = false;
2018-10-23 12:05:24 +02:00
text.vexpand = true;
text.buffer.changed.connect (validate);
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
scroll = new ScrolledWindow (null, null);
2019-03-11 15:14:37 +01:00
scroll.hscrollbar_policy = PolicyType.NEVER;
scroll.min_content_height = 120;
2018-10-23 12:05:24 +02:00
scroll.vexpand = true;
scroll.propagate_natural_height = true;
2018-05-04 16:23:26 +02:00
scroll.margin_start = 6;
scroll.margin_end = 6;
scroll.add (text);
scroll.show_all ();
2019-03-07 17:16:52 +01:00
attachments = new Widgets.AttachmentGrid (true);
2018-10-24 14:01:32 +02:00
counter = new Label ("");
2019-03-07 17:16:52 +01:00
2018-04-14 14:09:06 +02:00
actions.pack_start (counter, false, false, 6);
actions.pack_end (spoiler, false, false, 6);
2018-05-09 16:20:40 +02:00
actions.pack_end (visibility, false, false, 0);
actions.pack_end (attach, false, false, 6);
content.pack_start (spoiler_revealer, false, false, 6);
2018-05-09 16:20:40 +02:00
content.pack_start (scroll, false, false, 6);
content.pack_start (attachments, false, false, 6);
content.set_size_request (350, 120);
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
if (replying_to != null) {
spoiler.active = replying_to.sensitive;
var status_spoiler_text = replying_to.spoiler_text != null ? replying_to.spoiler_text : "";
spoiler_text.set_text (status_spoiler_text);
}
if (redrafting != null) {
spoiler.active = redrafting.sensitive;
var status_spoiler_text = redrafting.spoiler_text != null ? redrafting.spoiler_text : "";
spoiler_text.set_text (status_spoiler_text);
}
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
destroy.connect (() => dialog = null);
2019-03-07 17:16:52 +01:00
2018-05-09 16:20:40 +02:00
show_all ();
attachments.hide ();
text.grab_focus ();
validate ();
2018-04-14 14:09:06 +02:00
}
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
private MenuButton get_visibility_btn () {
var button = new MenuButton ();
var menu = new Popover (null);
var box = new Box (Orientation.VERTICAL, 6);
2018-10-23 12:05:24 +02:00
box.margin = 12;
2018-04-15 13:29:55 +02:00
menu.add (box);
2019-03-11 15:14:37 +01:00
button.direction = ArrowType.DOWN;
button.image = new Image.from_icon_name (visibility_opt.get_icon (), IconSize.BUTTON);
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
RadioButton? first = null;
foreach (API.StatusVisibility opt in API.StatusVisibility.get_all ()){
var item = new RadioButton.with_label_from_widget (first, opt.get_desc ());
if (first == null)
2018-04-15 13:29:55 +02:00
first = item;
2019-03-07 17:16:52 +01:00
2018-04-15 13:29:55 +02:00
item.toggled.connect (() => {
visibility_opt = opt;
2019-03-11 15:14:37 +01:00
(button.image as Image).icon_name = visibility_opt.get_icon ();
2018-04-15 13:29:55 +02:00
});
item.active = visibility_opt == opt;
2018-04-15 13:29:55 +02:00
box.pack_start (item, false, false, 0);
}
2019-03-07 17:16:52 +01:00
2018-04-15 13:29:55 +02:00
box.show_all ();
button.use_popover = true;
button.popover = menu;
2019-03-11 15:14:37 +01:00
button.valign = Align.CENTER;
2018-04-15 13:29:55 +02:00
button.show ();
return button;
}
2019-03-07 17:16:52 +01:00
private void validate () {
2019-03-09 15:45:16 +01:00
var remain = char_limit - text.buffer.get_char_count ();
2018-06-01 15:10:47 +02:00
if (spoiler.active)
2019-03-09 15:45:16 +01:00
remain -= (int)spoiler_text.buffer.length;
2019-03-07 17:16:52 +01:00
2018-04-15 14:28:23 +02:00
counter.label = remain.to_string ();
2019-03-07 17:16:52 +01:00
publish.sensitive = remain >= 0;
2018-04-14 14:09:06 +02:00
}
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
public static void open (string? text = null, API.Status? reply_to = null) {
if (dialog == null){
2019-03-11 15:14:37 +01:00
dialog = new Compose (reply_to);
2019-03-07 17:16:52 +01:00
if (text != null)
dialog.text.buffer.text = text;
2018-04-14 14:09:06 +02:00
}
else if (text != null)
2018-06-06 16:49:13 +02:00
dialog.text.buffer.text += text;
2018-04-14 14:09:06 +02:00
}
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
public static void reply (API.Status status) {
2018-10-24 14:01:32 +02:00
if (dialog != null)
return;
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
open (null, status);
dialog.text.buffer.text = status.get_reply_mentions ();
2018-04-24 16:50:38 +02:00
}
2019-03-07 17:16:52 +01:00
2019-03-11 15:14:37 +01:00
public static void redraft (API.Status status) {
2018-10-24 14:01:32 +02:00
if (dialog != null)
return;
2019-03-11 15:14:37 +01:00
dialog = new Compose (null, status);
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
if (status.attachments != null) {
2019-03-11 15:14:37 +01:00
foreach (API.Attachment attachment in status.attachments)
2018-10-24 14:01:32 +02:00
dialog.attachments.append (attachment);
}
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
var content = Html.simplify (status.content);
content = Html.remove_tags (content);
2019-03-11 15:14:37 +01:00
content = Widgets.RichLabel.restore_entities (content);
2018-10-24 14:01:32 +02:00
dialog.text.buffer.text = content;
}
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
private void publish_post () {
var pars = "?status=%s&visibility=%s".printf (Html.uri_encode (text.buffer.text), visibility_opt.to_string ());
2018-10-23 12:05:24 +02:00
pars += attachments.get_uri_array ();
2018-10-24 14:01:32 +02:00
if (replying_to != null)
pars += "&in_reply_to_id=%s".printf (replying_to.id.to_string ());
2019-03-07 17:16:52 +01:00
if (spoiler.active) {
pars += "&sensitive=true";
pars += "&spoiler_text=" + Html.uri_encode (spoiler_text.buffer.text);
}
2019-03-07 17:16:52 +01:00
2018-10-23 12:05:24 +02:00
var url = "%s/api/v1/statuses%s".printf (accounts.formal.instance, pars);
var msg = new Soup.Message ("POST", url);
2019-03-14 12:55:27 +01:00
network.inject (msg, Network.INJECT_TOKEN);
2018-10-24 14:01:32 +02:00
network.queue (msg, (sess, mess) => {
2019-03-14 12:55:27 +01:00
var root = network.parse (mess);
var status = API.Status.parse (root);
debug ("Posted: %s", status.id.to_string ()); //TODO: Live updates
destroy ();
2018-04-15 14:28:23 +02:00
});
}
2019-03-07 17:16:52 +01:00
2018-10-24 14:01:32 +02:00
private void redraft_post () {
2019-03-14 12:55:27 +01:00
redrafting.poof ((sess, msg) => {
publish_post ();
});
2018-10-24 14:01:32 +02:00
}
2018-04-14 14:09:06 +02:00
}