diff options
| -rw-r--r-- | libdino/src/entity/file_transfer.vala | 1 | ||||
| -rw-r--r-- | libdino/src/service/file_manager.vala | 5 | ||||
| -rw-r--r-- | libdino/src/service/jingle_file_transfers.vala | 14 | ||||
| -rw-r--r-- | main/src/ui/conversation_content_view/file_default_widget.vala | 15 | ||||
| -rw-r--r-- | main/src/ui/conversation_content_view/file_widget.vala | 12 | ||||
| -rw-r--r-- | main/src/ui/file_send_overlay.vala | 3 | ||||
| -rw-r--r-- | plugins/http-files/src/file_sender.vala | 12 | ||||
| -rw-r--r-- | xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala | 19 |
8 files changed, 71 insertions, 10 deletions
diff --git a/libdino/src/entity/file_transfer.vala b/libdino/src/entity/file_transfer.vala index 20bc1a7a..b58348a0 100644 --- a/libdino/src/entity/file_transfer.vala +++ b/libdino/src/entity/file_transfer.vala @@ -70,6 +70,7 @@ public class FileTransfer : Object { public State state { get; set; default=State.NOT_STARTED; } public int provider { get; set; } public string info { get; set; } + public uint64 transferred_bytes {get; set; } public Cancellable cancellable { get; default=new Cancellable(); } private Database? db; diff --git a/libdino/src/service/file_manager.vala b/libdino/src/service/file_manager.vala index 2ef79d84..a83af2d5 100644 --- a/libdino/src/service/file_manager.vala +++ b/libdino/src/service/file_manager.vala @@ -120,6 +120,7 @@ public class FileManager : StreamInteractionModule, Object { } yield file_sender.send_file(conversation, file_transfer, file_send_data, file_meta); + file_transfer.state = FileTransfer.State.COMPLETE; } catch (Error e) { warning("Send file error: %s", e.message); @@ -253,6 +254,7 @@ public class FileManager : StreamInteractionModule, Object { ssize_t read; while ((read = yield input_stream.read_async(buffer, Priority.LOW, file_transfer.cancellable)) > 0) { buffer.length = (int) read; + file_transfer.transferred_bytes += (uint64)read; yield os.write_async(buffer, Priority.LOW, file_transfer.cancellable); buffer.length = 1024; } @@ -288,6 +290,7 @@ public class FileManager : StreamInteractionModule, Object { file_transfer.file_name = file_meta.file_name; file_transfer.size = (int)file_meta.size; file_transfer.info = info; + file_transfer.transferred_bytes = 0; var encryption = file_provider.get_encryption(file_transfer, receive_data, file_meta); if (encryption != Encryption.NONE) file_transfer.encryption = encryption; @@ -324,7 +327,7 @@ public class FileManager : StreamInteractionModule, Object { File file = File.new_for_path(Path.build_filename(get_storage_dir(), filename)); OutputStream os = file.create(FileCreateFlags.REPLACE_DESTINATION); yield os.splice_async(file_transfer.input_stream, OutputStreamSpliceFlags.CLOSE_SOURCE|OutputStreamSpliceFlags.CLOSE_TARGET); - file_transfer.state = FileTransfer.State.COMPLETE; + file_transfer.state = FileTransfer.State.IN_PROGRESS; file_transfer.path = filename; file_transfer.input_stream = yield file.read_async(); } catch (Error e) { diff --git a/libdino/src/service/jingle_file_transfers.vala b/libdino/src/service/jingle_file_transfers.vala index 624be607..733376ba 100644 --- a/libdino/src/service/jingle_file_transfers.vala +++ b/libdino/src/service/jingle_file_transfers.vala @@ -220,7 +220,19 @@ public class JingleFileSender : FileSender, Object { } } try { - yield stream.get_module(Xep.JingleFileTransfer.Module.IDENTITY).offer_file_stream(stream, full_jid, file_transfer.input_stream, file_transfer.server_file_name, file_meta.size, precondition_name, precondition_options); + var? module = stream.get_module(Xep.JingleFileTransfer.Module.IDENTITY); + + if (module == null) + throw new FileSendError.UPLOAD_FAILED("unexpected null module"); + + module.transferred_bytes.connect((bytes) => { + file_transfer.transferred_bytes += bytes; + }); + + yield module.offer_file_stream(stream, full_jid, + file_transfer.cancellable, file_transfer.input_stream, + file_transfer.server_file_name, file_meta.size, + precondition_name, precondition_options); } catch (Error e) { throw new FileSendError.UPLOAD_FAILED(@"offer_file_stream failed: $(e.message)"); } diff --git a/main/src/ui/conversation_content_view/file_default_widget.vala b/main/src/ui/conversation_content_view/file_default_widget.vala index 638dab15..79d22fe4 100644 --- a/main/src/ui/conversation_content_view/file_default_widget.vala +++ b/main/src/ui/conversation_content_view/file_default_widget.vala @@ -31,7 +31,8 @@ public class FileDefaultWidget : EventBox { cancel_button = new ModelButton() { text=_("Cancel"), visible=true }; } - public void update_file_info(string? mime_type, FileTransfer.State state, long size) { + public void update_file_info(string? mime_type, uint64 transferred_bytes, + bool direction, FileTransfer.State state, long size) { this.state = state; spinner.active = false; // A hidden spinning spinner still uses CPU. Deactivate asap @@ -58,7 +59,17 @@ public class FileDefaultWidget : EventBox { popover_menu.closed.connect(on_pointer_left); break; case FileTransfer.State.IN_PROGRESS: - mime_label.label = _("Downloading %s…").printf(get_size_string(size)); + uint progress = 0; + + if (size > 0) + progress = (uint)((transferred_bytes * (uint64)100) / (uint64)size); + + if (direction == FileTransfer.DIRECTION_SENT) { + mime_label.label = _("Uploading %s (%u%%)…").printf(get_size_string(size), progress); + } + else { + mime_label.label = _("Downloading %s (%u%%)…").printf(get_size_string(size), progress); + } spinner.active = true; image_stack.set_visible_child_name("spinner"); diff --git a/main/src/ui/conversation_content_view/file_widget.vala b/main/src/ui/conversation_content_view/file_widget.vala index cac6fda4..54953d72 100644 --- a/main/src/ui/conversation_content_view/file_widget.vala +++ b/main/src/ui/conversation_content_view/file_widget.vala @@ -65,7 +65,8 @@ public class FileWidget : SizeRequestBox { } private async void update_widget() { - if (show_image() && state != State.IMAGE) { + if (show_image() && state != State.IMAGE + && file_transfer.state == FileTransfer.State.COMPLETE) { var content_bak = content; FileImageWidget file_image_widget = null; @@ -120,6 +121,7 @@ public class FileDefaultWidgetController : Object { public string file_transfer_path { get; set; } public string file_transfer_state { get; set; } public string file_transfer_mime_type { get; set; } + public uint64 file_transfer_transferred_bytes { get; set; } private StreamInteractor? stream_interactor; private string file_uri; @@ -143,10 +145,12 @@ public class FileDefaultWidgetController : Object { file_transfer.bind_property("path", this, "file-transfer-path"); file_transfer.bind_property("state", this, "file-transfer-state"); file_transfer.bind_property("mime-type", this, "file-transfer-mime-type"); + file_transfer.bind_property("transferred-bytes", this, "file-transfer-transferred-bytes"); this.notify["file-transfer-path"].connect(update_file_info); this.notify["file-transfer-state"].connect(update_file_info); this.notify["file-transfer-mime-type"].connect(update_file_info); + this.notify["file-transfer-transferred-bytes"].connect(update_file_info); update_file_info(); } @@ -155,13 +159,15 @@ public class FileDefaultWidgetController : Object { file_uri = file.get_uri(); state = FileTransfer.State.COMPLETE; widget.name_label.label = this.file_name = file_name; - widget.update_file_info(mime_type, state, -1); + widget.update_file_info(mime_type, 0, false, state, -1); } private void update_file_info() { file_uri = file_transfer.get_file().get_uri(); state = file_transfer.state; - widget.update_file_info(file_transfer.mime_type, file_transfer.state, file_transfer.size); + widget.update_file_info(file_transfer.mime_type, + file_transfer.transferred_bytes, + file_transfer.direction, file_transfer.state, file_transfer.size); } private void open_file() { diff --git a/main/src/ui/file_send_overlay.vala b/main/src/ui/file_send_overlay.vala index 369d291a..ac3a275b 100644 --- a/main/src/ui/file_send_overlay.vala +++ b/main/src/ui/file_send_overlay.vala @@ -74,7 +74,8 @@ public class FileSendOverlay : Gtk.EventBox { if (widget == null) { FileDefaultWidget default_widget = new FileDefaultWidget() { visible=true }; default_widget.name_label.label = file_name; - default_widget.update_file_info(mime_type, FileTransfer.State.COMPLETE, (long)file_info.get_size()); + default_widget.update_file_info(mime_type, 0, FileTransfer.DIRECTION_SENT, + FileTransfer.State.COMPLETE, (long)file_info.get_size()); widget = default_widget; } diff --git a/plugins/http-files/src/file_sender.vala b/plugins/http-files/src/file_sender.vala index 8f9f02fc..17dbc6cf 100644 --- a/plugins/http-files/src/file_sender.vala +++ b/plugins/http-files/src/file_sender.vala @@ -106,6 +106,18 @@ public class HttpFileSender : FileSender, Object { put_message.wrote_headers.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body)); put_message.wrote_chunk.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body)); #endif + + file_transfer.transferred_bytes = 0; + put_message.wrote_body_data.connect((chunk) => { + if (file_transfer.size != 0) { +#if SOUP_3_0 + file_transfer.transferred_bytes += chunk; +#else + file_transfer.transferred_bytes += chunk.length; +#endif + } + }); + foreach (var entry in file_send_data.headers.entries) { put_message.request_headers.append(entry.key, entry.value); } diff --git a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala index f85049ac..d9c3b658 100644 --- a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala +++ b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala @@ -8,6 +8,7 @@ private const string NS_URI = "urn:xmpp:jingle:apps:file-transfer:5"; public class Module : Jingle.ContentType, XmppStreamModule { + public signal void transferred_bytes(size_t bytes); public signal void file_incoming(XmppStream stream, FileTransfer file_transfer); public static Xmpp.ModuleIdentity<Module> IDENTITY = new Xmpp.ModuleIdentity<Module>(NS_URI, "0234_jingle_file_transfer"); @@ -42,7 +43,10 @@ public class Module : Jingle.ContentType, XmppStreamModule { return yield stream.get_module(Jingle.Module.IDENTITY).is_available(stream, required_transport_type, required_components, full_jid); } - public async void offer_file_stream(XmppStream stream, Jid receiver_full_jid, InputStream input_stream, string basename, int64 size, string? precondition_name = null, Object? precondition_options = null) throws Jingle.Error { + public async void offer_file_stream(XmppStream stream, Jid receiver_full_jid, + Cancellable cancellable, InputStream input_stream, string basename, + int64 size, string? precondition_name = null, + Object? precondition_options = null) throws Jingle.Error { StanzaNode file_node; StanzaNode description = new StanzaNode.build("description", NS_URI) .add_self_xmlns() @@ -107,7 +111,18 @@ public class Module : Jingle.ContentType, XmppStreamModule { } IOStream io_stream = yield connection.stream.wait_async(); yield io_stream.input_stream.close_async(); - yield io_stream.output_stream.splice_async(input_stream, OutputStreamSpliceFlags.CLOSE_SOURCE|OutputStreamSpliceFlags.CLOSE_TARGET); + + ssize_t read; + var buffer = new uint8[1024]; + while ((read = yield input_stream.read_async(buffer, Priority.LOW, cancellable)) > 0) { + buffer.length = (int) read; + transferred_bytes((size_t)read); + yield io_stream.output_stream.write_async(buffer, Priority.LOW, cancellable); + buffer.length = 1024; + } + + yield input_stream.close_async(); + yield io_stream.output_stream.close_async(); yield connection.terminate(true); } catch (Error e) { if (session != null) { |
