aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/conversation_content_view/file_transmission_progress.vala
diff options
context:
space:
mode:
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.vala120
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