Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Composer: Initial work for attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
bleakgrey committed Aug 31, 2021
1 parent 0c10bee commit ddba63d
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 148 deletions.
2 changes: 1 addition & 1 deletion data/ui/dialogs/compose.ui
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</child>
<child type="start">
<object class="GtkButton" id="close_button">
<property name="label" translatable="yes">Close</property>
<property name="label" translatable="yes">Cancel</property>
<signal name="clicked" handler="on_close" swapped="no"/>
</object>
</child>
Expand Down
132 changes: 59 additions & 73 deletions src/API/Attachment.vala
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
public class Tootle.API.Attachment : Entity, Widgetizable {

// https://github.com/tootsuite/mastodon/blob/master/app/models/media_attachment.rb
public const string[] SUPPORTED_MIMES = {
"image/jpeg",
"image/png",
"image/gif",
"video/webm",
"video/mp4",
"video/quicktime",
"video/ogg",
"video/webm",
"video/quicktime",
"audio/wave",
"audio/wav",
"audio/x-wav",
"audio/x-pn-wave",
"audio/ogg",
"audio/mpeg",
"audio/mp3",
"audio/webm",
"audio/flac",
"audio/aac",
"audio/m4a",
"audio/x-m4a",
"audio/mp4",
"audio/3gpp",
"video/x-ms-asf"
};

public string id { get; set; }
public string kind { get; set; default = "unknown"; }
public string url { get; set; }
Expand All @@ -38,58 +10,72 @@ public class Tootle.API.Attachment : Entity, Widgetizable {
get { return (this._preview_url == null || this._preview_url == "") ? url : _preview_url; }
}

public static async Attachment upload (string uri, string title, string? descr) throws Error {
message (@"Uploading new media: $(uri)...");
public File? source_file { get; set; }

uint8[] contents;
string mime;
GLib.FileInfo type;
try {
GLib.File file = File.new_for_uri (uri);
file.load_contents (null, out contents, null);
type = file.query_info (GLib.FileAttribute.STANDARD_CONTENT_TYPE, 0);
mime = type.get_content_type ();
}
catch (Error e) {
throw new Oopsie.USER (_("Can't open file $file:\n$reason")
.replace ("$file", title)
.replace ("$reason", e.message)
);
public bool is_published {
get {
return this.source_file == null;
}
}

var descr_param = "";
if (descr != null && descr.replace (" ", "") != "") {
descr_param = "?description=" + HtmlUtils.uri_encode (descr);
}
public static Attachment upload (File file) {
return new Attachment () {
source_file = file
};
}

var buffer = new Soup.Buffer.take (contents);
var multipart = new Soup.Multipart (Soup.FORM_MIME_TYPE_MULTIPART);
multipart.append_form_file ("file", mime.replace ("/", "."), mime, buffer);
var url = @"$(accounts.active.instance)/api/v1/media$descr_param";
var msg = Soup.Form.request_new_from_multipart (url, multipart);
msg.request_headers.append ("Authorization", @"Bearer $(accounts.active.access_token)");
// public static async Attachment upload (string uri, string title, string? descr) throws Error {
// message (@"Uploading new media: $(uri)...");

string? error = null;
network.queue (msg,
(sess, mess) => {
upload.callback ();
},
(code, reason) => {
error = reason;
upload.callback ();
});
// uint8[] contents;
// string mime;
// GLib.FileInfo type;
// try {
// GLib.File file = File.new_for_uri (uri);
// file.load_contents (null, out contents, null);
// type = file.query_info (GLib.FileAttribute.STANDARD_CONTENT_TYPE, 0);
// mime = type.get_content_type ();
// }
// catch (Error e) {
// throw new Oopsie.USER (_("Can't open file $file:\n$reason")
// .replace ("$file", title)
// .replace ("$reason", e.message)
// );
// }

yield;
// var descr_param = "";
// if (descr != null && descr.replace (" ", "") != "") {
// descr_param = "?description=" + HtmlUtils.uri_encode (descr);
// }

if (error != null)
throw new Oopsie.INSTANCE (error);
else {
var node = network.parse_node (msg);
var entity = accounts.active.create_entity<API.Attachment> (node);
message (@"OK! ID $(entity.id)");
return entity;
}
}
// var buffer = new Soup.Buffer.take (contents);
// var multipart = new Soup.Multipart (Soup.FORM_MIME_TYPE_MULTIPART);
// multipart.append_form_file ("file", mime.replace ("/", "."), mime, buffer);
// var url = @"$(accounts.active.instance)/api/v1/media$descr_param";
// var msg = Soup.Form.request_new_from_multipart (url, multipart);
// msg.request_headers.append ("Authorization", @"Bearer $(accounts.active.access_token)");

// string? error = null;
// network.queue (msg,
// (sess, mess) => {
// upload.callback ();
// },
// (code, reason) => {
// error = reason;
// upload.callback ();
// });

// yield;

// if (error != null)
// throw new Oopsie.INSTANCE (error);
// else {
// var node = network.parse_node (msg);
// var entity = accounts.active.create_entity<API.Attachment> (node);
// message (@"OK! ID $(entity.id)");
// return entity;
// }
// }

public override Gtk.Widget to_widget () {
if (preview_url != null) {
Expand Down
110 changes: 110 additions & 0 deletions src/Dialogs/Composer/AttachmentsPage.vala
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
using Gtk;

public class Tootle.AttachmentsPage : ComposerPage {

// https://github.com/tootsuite/mastodon/blob/master/app/models/media_attachment.rb
public const string[] SUPPORTED_MIMES = {
"image/jpeg",
"image/png",
"image/gif",
"video/webm",
"video/mp4",
"video/quicktime",
"video/ogg",
"video/webm",
"audio/wave",
"audio/wav",
"audio/x-wav",
"audio/x-pn-wave",
"audio/ogg",
"audio/mpeg",
"audio/mp3",
"audio/webm",
"audio/flac",
"audio/aac",
"audio/m4a",
"audio/x-m4a",
"audio/mp4",
"audio/3gpp",
"video/x-ms-asf"
};

public GLib.ListStore attachments;

public AttachmentsPage () {
Object (
title: _("Media"),
icon_name: "mail-attachment-symbolic"
);

attachments = new GLib.ListStore (typeof (API.Attachment));
attachments.items_changed.connect (on_attachments_changed);
}

protected Adw.ViewStack stack;
protected Adw.StatusPage empty_state;
protected ListBox list;

public override void on_build (Dialogs.Compose dialog, API.Status status) {
base.on_build (dialog, status);

// Empty state
var attach_button = new Button.with_label (_("Add Media")) {
halign = Align.CENTER
};
attach_button.clicked.connect (show_file_selector);

empty_state = new Adw.StatusPage () {
title = _("No Media"),
description = _("Drag files here or click the button below"),
vexpand = true,
icon_name = icon_name,
child = attach_button
};
empty_state.add_css_class ("compact");

// Non-empty state
list = new ListBox ();
list.bind_model (attachments, on_create_list_item);

// State stack
stack = new Adw.ViewStack ();
stack.add_named (list, "list");
stack.add_named (empty_state, "empty");
content.prepend (stack);
}

public override void on_pull () {
on_attachments_changed ();
}

Widget on_create_list_item (Object item) {
var attachment = item as API.Attachment;
return new Label (attachment.source_file.get_uri ());
}

void on_attachments_changed () {
var is_empty = attachments.get_n_items () < 1;
stack.visible_child_name = (is_empty ? "empty" : "list");
}

void show_file_selector () {
var filter = new FileFilter () {
name = _("All Supported Files")
};
foreach (var mime_type in SUPPORTED_MIMES) {
filter.add_mime_type (mime_type);
}

var chooser = new FileChooserNative (_("Open"), dialog, Gtk.FileChooserAction.OPEN, null, null) {
select_multiple = true,
filter = filter
};
chooser.response.connect (id => {
switch (id) {
case ResponseType.ACCEPT:
var files = chooser.get_files ();
for (var i = 0; i < chooser.get_files ().get_n_items (); i++) {
var file = files.get_item (i) as File;
var attachment = API.Attachment.upload (file);
attachments.append (attachment);
}
break;
}
chooser.unref ();
});
chooser.ref ();
chooser.show ();
}

}
10 changes: 8 additions & 2 deletions src/Dialogs/Composer/Dialog.vala
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ public class Tootle.Dialogs.Compose : Adw.Window {
set { commit_button.add_css_class (value); }
}

ulong build_sigid;

construct {
transient_for = app.main_window;
title_switcher.stack = stack;

notify["status"].connect (() => {
build_sigid = notify["status"].connect (() => {
build ();
present ();

disconnect (build_sigid);
});
}

Expand Down Expand Up @@ -80,7 +84,9 @@ public class Tootle.Dialogs.Compose : Adw.Window {
protected void add_page (ComposerPage page) {
var wrapper = stack.add (page);
page.on_build (this, this.status);
modify_req.connect (page.on_sync);
page.on_pull ();

modify_req.connect (page.on_push);
modify_req.connect (page.on_modify_req);
page.bind_property ("visible", wrapper, "visible", GLib.BindingFlags.SYNC_CREATE);
page.bind_property ("title", wrapper, "title", GLib.BindingFlags.SYNC_CREATE);
Expand Down
7 changes: 4 additions & 3 deletions src/Dialogs/Composer/EditorPage.vala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public class Tootle.EditorPage : ComposerPage {
base.on_build (dialog, status);

install_editor ();
populate_editor ();
install_visibility ();
install_cw ();

Expand All @@ -27,9 +26,11 @@ public class Tootle.EditorPage : ComposerPage {
recount_chars ();
}

public override void on_sync () {
warning ("syncing");
public override void on_pull () {
populate_editor ();
}

public override void on_push () {
status.content = editor.buffer.text;
status.sensitive = cw_button.active;
if (status.sensitive) {
Expand Down
8 changes: 5 additions & 3 deletions src/Dialogs/Composer/Page.vala
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ public class Tootle.ComposerPage : Gtk.Box {
bottom_bar.show ();
}

// This is used to populate the UI with the status entity data
public virtual void on_build (Dialogs.Compose dialog, API.Status status) {
this.dialog = dialog;
this.status = status;
}

// This is used to push data back to the status entity
public virtual void on_sync () {}
// Entity -> UI state
public virtual void on_pull () {}

// UI state -> Entity
public virtual void on_push () {}

public virtual void on_modify_req (Request req) {}

Expand Down
Loading

0 comments on commit ddba63d

Please sign in to comment.