improve upload progress window

Wed, 07 Feb 2024 17:10:01 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 07 Feb 2024 17:10:01 +0100
changeset 20
db263186edf3
parent 19
813c97c5b6d3
child 21
3060a5a1d5fd

improve upload progress window

application/davcontroller.c file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/utils.c file | annotate | diff | comparison | revisions
libidav/utils.h file | annotate | diff | comparison | revisions
--- a/application/davcontroller.c	Tue Feb 06 19:01:52 2024 +0100
+++ b/application/davcontroller.c	Wed Feb 07 17:10:01 2024 +0100
@@ -255,10 +255,18 @@
     size_t uploaded_files;
     size_t uploaded_directories;
 
+    DavBool upload_file;
+    size_t current_file_size;
+    size_t current_file_upload;
+
+    char *current_file_name;
+
     UiObject *dialog;
     UiDouble *progress;
-    UiString *file_label;
-    UiString *speed_label;
+    UiString *label_top_left;
+    UiString *label_top_right;
+    UiString *label_bottom_left;
+    UiString *label_bottom_right;
 } DavFileUpload;
 
 typedef struct DUFile {
@@ -274,6 +282,76 @@
     return ((double)upload->uploaded_bytes / (double)upload->total_bytes) * 100;
 }
 
+static void update_upload_labels(DavFileUpload *upload) {
+    char *sz_total = util_size_str(FALSE, upload->total_bytes);
+    char *sz_uploaded = util_size_str2(FALSE, upload->uploaded_bytes, upload->total_bytes, 2);
+    char *sz_uploaded_end = strchr(sz_uploaded, ' ');
+    if (sz_uploaded_end) {
+        *sz_uploaded_end = 0;
+    }
+
+    cxmutstr label1 = cx_asprintf(
+        "%s/%s   %zu/%zu files",
+        sz_uploaded,
+        sz_total,
+        upload->uploaded_files+upload->uploaded_directories,
+        upload->total_files+upload->total_directories);
+    ui_set(upload->label_top_left, label1.ptr);
+
+    free(sz_total);
+    free(label1.ptr);
+
+
+    cxmutstr file_label = cx_asprintf("%s (%.0f%%)", upload->current_file_name, ((float)upload->current_file_upload/(float)upload->current_file_size)*100);
+    ui_set(upload->label_top_right, file_label.ptr);
+
+    free(file_label.ptr);
+}
+
+static int uithr_update_upload_labels(void *data) {
+    update_upload_labels(data);
+    return 0;
+}
+
+static void upload_dav_progress(DavResource *res, int64_t total, int64_t now, void *data) {
+    DavFileUpload *upload = data;
+    if (upload->upload_file) {
+        if (now > upload->current_file_size) {
+            // current_file_size is not accurate (either the file was changed after the last stat
+            // or we have some extra bytes because of encryption
+            // adjust current_file_size and the total upload size
+            int64_t extra = now - upload->current_file_size;
+            upload->current_file_size += extra;
+            upload->total_bytes += extra;
+        }
+
+        int64_t new_progress = now - upload->current_file_upload;
+        upload->uploaded_bytes += new_progress;
+        upload->current_file_upload = now;
+
+        ui_call_mainthread(uithr_update_upload_labels, upload);
+    }
+}
+
+
+typedef struct FileNameUpdate {
+    DavFileUpload *upload;
+    char *name;
+} FileNameUpdate;
+
+static int uithr_update_file_label(FileNameUpdate *update) {
+    // replace upload->current_filename with update->name
+    if (update->upload->current_file_name) {
+        free(update->upload->current_file_name);
+    }
+    update->upload->current_file_name = update->name;
+
+    ui_set(update->upload->label_top_right, update->name);
+
+    free(update);
+    return 0;
+}
+
 static int qthr_file_upload(void *data) {
     DUFile *f = data;
     DavFileUpload *upload = f->upload;
@@ -285,7 +363,17 @@
         return 0;
     }
 
+    upload->upload_file = TRUE;
+    upload->current_file_size = f->bytes;
+    upload->current_file_upload = 0;
+
     DavResource *res = dav_resource_new(sn, f->upload_path);
+
+    FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
+    ui_update->upload = upload;
+    ui_update->name = strdup(res->name);
+    ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
+
     dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)fseek);
     if (dav_store(res)) {
         f->error = sn->error;
@@ -294,6 +382,8 @@
 
     fclose(in);
 
+    upload->upload_file = FALSE;
+
     return 0;
 }
 
@@ -302,11 +392,13 @@
     DavFileUpload *upload = file->upload;
 
     upload->uploaded_files++;
-    upload->uploaded_bytes += file->bytes;
+    //upload->uploaded_bytes += file->bytes;
 
     double progress = upload_progress(upload);
     ui_set(upload->progress, upload_progress(upload));
 
+    update_upload_labels(upload);
+
     free(file->path);
     free(file->upload_path);
 }
@@ -319,6 +411,11 @@
     DavResource *res = dav_resource_new(sn, f->upload_path);
     res->iscollection = TRUE;
 
+    FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
+    ui_update->upload = upload;
+    ui_update->name = strdup(res->name);
+    ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
+
     if (dav_create(res)) {
         f->error = sn->error;
     }
@@ -334,6 +431,8 @@
 
     upload->uploaded_directories++;
 
+    update_upload_labels(upload);
+
     free(file->path);
     free(file->upload_path);
 }
@@ -372,7 +471,7 @@
         cxListRemove(stack, 0);
 
         SYS_STAT s;
-        if (!stat(f->path, &s)) {
+        if (!sys_stat(f->path, &s)) {
             if (S_ISDIR(s.st_mode)) {
                 f->isdirectory = TRUE;
                 upload->total_directories++;
@@ -421,6 +520,8 @@
 
 static void uithr_upload_scan_finished(UiEvent *event, void *data) {
     DavFileUpload *upload = data;
+
+    update_upload_labels(upload);
 }
 
 
@@ -437,6 +538,8 @@
     DavFileUpload *upload = malloc(sizeof(DavFileUpload));
     memset(upload, 0, sizeof(DavFileUpload));
 
+    dav_session_set_progresscallback(upload_session, NULL, upload_dav_progress, upload);
+
     upload->ui = ui;
     upload->browser = browser;
     upload->sn = upload_session;
@@ -445,21 +548,34 @@
     upload->queue = ui_threadpool_create(1);
 
     // create upload progress window
-    UiObject *dialog = ui_simple_window("Upload", upload);
+    cxmutstr wtitle = cx_asprintf("Upload to: %s", ui_get(browser->path));
+    UiObject *dialog = ui_simple_window(wtitle.ptr, upload);
+    free(wtitle.ptr);
     upload->dialog = dialog;
-    ui_window_size(dialog, 450, 120);
+    ui_window_size(dialog, 550, 120);
     upload->progress = ui_double_new(dialog->ctx, NULL);
-    upload->file_label = ui_string_new(dialog->ctx, NULL);
-    upload->speed_label = ui_string_new(dialog->ctx, NULL);
+    upload->label_top_left = ui_string_new(dialog->ctx, NULL);
+    upload->label_top_right = ui_string_new(dialog->ctx, NULL);
+    upload->label_bottom_left = ui_string_new(dialog->ctx, NULL);
+    upload->label_bottom_right = ui_string_new(dialog->ctx, NULL);
 
-    ui_vbox(dialog, .margin = 10, .spacing = 10) {
-        ui_llabel(dialog, .value = upload->file_label);
-        ui_progressbar(dialog, .value = upload->progress);
-        ui_llabel(dialog, .value = upload->speed_label);
+    ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) {
+        ui_llabel(dialog, .value = upload->label_top_left, .hexpand = TRUE);
+        ui_rlabel(dialog, .value = upload->label_top_right);
+        ui_newline(dialog);
+
+        ui_progressbar(dialog, .value = upload->progress, .colspan = 2, .hexpand = TRUE);
+        ui_newline(dialog);
+
+        ui_llabel(dialog, .value = upload->label_bottom_left);
+        ui_rlabel(dialog, .value = upload->label_bottom_right);
+        ui_newline(dialog);
     }
 
-    ui_set(upload->file_label, "");
-    ui_set(upload->speed_label, "");
+    ui_set(upload->label_top_left, "");
+    ui_set(upload->label_top_right, "");
+    ui_set(upload->label_bottom_left, "");
+    ui_set(upload->label_bottom_right, "");
     ui_set(upload->progress, 0);
 
     ui_show(dialog);
--- a/libidav/resource.c	Tue Feb 06 19:01:52 2024 +0100
+++ b/libidav/resource.c	Wed Feb 07 17:10:01 2024 +0100
@@ -856,6 +856,10 @@
     
     // store content
     if(data->content) {
+        curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, dav_session_put_progress);
+        curl_easy_setopt(sn->handle, CURLOPT_XFERINFODATA, res);
+        curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 0L);
+
         int encryption = DAV_ENCRYPT_CONTENT(sn) && sn->key;
         CURLcode ret;
         if(encryption) {
@@ -900,6 +904,8 @@
             // TODO: store the properties later
             if(resource_add_crypto_info(sn, res->href, res->name, enc_hash)) {
                 free(enc_hash);
+                curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, NULL);
+                curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 1L);
                 return 1;
             }
             resource_add_string_property(res, DAV_NS, "crypto-hash", enc_hash);
@@ -948,6 +954,9 @@
                     data->seek,
                     data->length);
         }
+
+        curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, NULL);
+        curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 1L);
         
         long status = 0;
         curl_easy_getinfo(sn->handle, CURLINFO_RESPONSE_CODE, &status);
--- a/libidav/utils.c	Tue Feb 06 19:01:52 2024 +0100
+++ b/libidav/utils.c	Wed Feb 07 17:10:01 2024 +0100
@@ -784,50 +784,54 @@
 }
 
 char* util_size_str(DavBool iscollection, uint64_t contentlength) {
+    return util_size_str2(iscollection, contentlength, contentlength, 1);
+}
+
+char* util_size_str2(DavBool iscollection, uint64_t contentlength, uint64_t dimension, int precision) {
     char *str = malloc(16);
     uint64_t size = contentlength;
-    
+
     if(iscollection) {
         str[0] = '\0'; // currently no information for collections
-    } else if(size < 0x400) {
+    } else if(dimension < 0x400) {
         snprintf(str, 16, "%" PRIu64 " bytes", size);
-    } else if(size < 0x100000) {
+    } else if(dimension < 0x100000) {
         float s = (float)size/0x400;
         int diff = (s*100 - (int)s*100);
         if(diff > 90) {
             diff = 0;
             s += 0.10f;
         }
-        if(size < 0x2800 && diff != 0) {
+        if(dimension < 0x2800 && diff != 0) {
             // size < 10 KiB
-            snprintf(str, 16, "%.1f KiB", s);
+            snprintf(str, 16, "%.*f KiB", precision, s);
         } else {
             snprintf(str, 16, "%.0f KiB", s);
         }
-    } else if(size < 0x40000000) {
+    } else if(dimension < 0x40000000) {
         float s = (float)size/0x100000;
         int diff = (s*100 - (int)s*100);
         if(diff > 90) {
             diff = 0;
             s += 0.10f;
         }
-        if(size < 0xa00000 && diff != 0) {
+        if(dimension < 0xa00000 && diff != 0) {
             // size < 10 MiB
-            snprintf(str, 16, "%.1f MiB", s);
+            snprintf(str, 16, "%.*f MiB", precision, s);
         } else {
             size /= 0x100000;
             snprintf(str, 16, "%.0f MiB", s);
         }
-    } else if(size < 0x1000000000ULL) {
+    } else if(dimension < 0x1000000000ULL) {
         float s = (float)size/0x40000000;
         int diff = (s*100 - (int)s*100);
         if(diff > 90) {
             diff = 0;
             s += 0.10f;
         }
-        if(size < 0x280000000 && diff != 0) {
+        if(dimension < 0x280000000 && diff != 0) {
             // size < 10 GiB
-            snprintf(str, 16, "%.1f GiB", s);
+            snprintf(str, 16, "%.*f GiB", precision, s);
         } else {
             size /= 0x40000000;
             snprintf(str, 16, "%.0f GiB", s);
@@ -840,9 +844,9 @@
             diff = 0;
             s += 0.10f;
         }
-        if(size < 0x280000000 && diff != 0) {
+        if(dimension < 0x280000000 && diff != 0) {
             // size < 10 TiB
-            snprintf(str, 16, "%.1f TiB", s);
+            snprintf(str, 16, "%.*f TiB", precision, s);
         } else {
             size /= 0x40000000;
             snprintf(str, 16, "%.0f TiB", s);
--- a/libidav/utils.h	Tue Feb 06 19:01:52 2024 +0100
+++ b/libidav/utils.h	Wed Feb 07 17:10:01 2024 +0100
@@ -105,6 +105,7 @@
 char* util_sys_parent_path(const char *path);
 
 char* util_size_str(DavBool iscollection, uint64_t contentlength);
+char* util_size_str2(DavBool iscollection, uint64_t contentlength, uint64_t dimension, int precision);
 char* util_date_str(time_t tm);
 
 int util_getboolean(const char *v);

mercurial