Wed, 07 Feb 2024 17:10:01 +0100
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);