diff options
Diffstat (limited to 'main/src/ui/conversation_content_view/file_transmission_progress.vala')
-rw-r--r-- | main/src/ui/conversation_content_view/file_transmission_progress.vala | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/main/src/ui/conversation_content_view/file_transmission_progress.vala b/main/src/ui/conversation_content_view/file_transmission_progress.vala new file mode 100644 index 00000000..bf3f377b --- /dev/null +++ b/main/src/ui/conversation_content_view/file_transmission_progress.vala @@ -0,0 +1,120 @@ +using Gee; +using Gdk; +using Gtk; +using Xmpp; + +using Dino.Entities; + +namespace Dino.Ui { + + public class FileTransmissionProgress : Adw.Bin { + + public enum State { + UNKNOWN_SOURCE, + DOWNLOAD_NOT_STARTED, + DOWNLOAD_NOT_STARTED_FAILED_BEFORE, + DOWNLOADING, + UPLOADING + } + + public int64 file_size { get; set; } + public int64 transferred_size { get; set; } + public State state { get; set; } + + private CssProvider css_provider = new CssProvider(); + private Button button = new Button(); + + private uint64 next_update_time = 0; + private int64 last_progress_percent = 0; + private uint update_progress_timeout_id = -1; + + construct { + add_css_class("circular-loading-indicator"); + + button.add_css_class("circular"); + Adw.Bin holder = new Adw.Bin(); + holder.set_child(button); + this.set_child(holder); + + this.button.clicked.connect(on_button_clicked); + + this.notify["transferred-size"].connect(on_transferred_size_update); + this.notify["state"].connect(on_state_changed); + on_state_changed(); + } + + private void on_transferred_size_update() { + if (update_progress_timeout_id == -1) { + int64 progress_percent = transferred_size * 100 / file_size; + if (progress_percent != last_progress_percent) { + uint64 time_now = get_monotonic_time() / 1000; + if (next_update_time > time_now) { + update_progress_timeout_id = Timeout.add((uint) (next_update_time - time_now), () => { + update_progress(); + update_progress_timeout_id = -1; + return Source.REMOVE; + }); + } else { + update_progress(); + } + } + } + } + + private void on_state_changed() { + sensitive = state != UNKNOWN_SOURCE; + + switch (this.state) { + case UNKNOWN_SOURCE: + case DOWNLOAD_NOT_STARTED: + button.icon_name = "document-save-symbolic"; + break; + case DOWNLOADING: + case UPLOADING: + button.icon_name = "small-x-symbolic"; + break; + case DOWNLOAD_NOT_STARTED_FAILED_BEFORE: + button.icon_name = "dialog-warning-symbolic"; + break; + } + } + + private void update_progress() { + this.get_style_context().remove_provider(css_provider); + css_provider = new CssProvider(); + int64 progress_percent = transferred_size * 100 / file_size; + + css_provider.load_from_string(@" + .circular-loading-indicator { + background-image: conic-gradient(@accent_color $(progress_percent)%, transparent $(progress_percent)%); + } + "); + + this.get_style_context().add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + next_update_time = get_monotonic_time() / 1000 + 500; + last_progress_percent = progress_percent; + } + + private void on_button_clicked() { + switch (this.state) { + case UNKNOWN_SOURCE: + break; + case DOWNLOAD_NOT_STARTED_FAILED_BEFORE: + case DOWNLOAD_NOT_STARTED: + this.activate_action("file.download", null); + break; + case DOWNLOADING: + case UPLOADING: + this.activate_action("file.cancel", null); + break; + } + } + + public override void dispose() { + if (update_progress_timeout_id != -1) { + Source.remove(update_progress_timeout_id); + update_progress_timeout_id = -1; + } + } + } +}
\ No newline at end of file |