Replace animated background for progress bar on home page

This commit is contained in:
2021-06-29 12:07:49 +02:00
parent 04384865cf
commit 4d140ad5a2
3 changed files with 110 additions and 79 deletions

View File

@@ -67,12 +67,12 @@
.feat_table > div > div.round_br { border-bottom-right-radius: 0.5em; } .feat_table > div > div.round_br { border-bottom-right-radius: 0.5em; }
.feat_table > div > div.round_bl { border-bottom-left-radius: 0.5em; } .feat_table > div > div.round_bl { border-bottom-left-radius: 0.5em; }
{{template `modal.css`}} {{ template `modal.css` }}
</style> </style>
<script>window.api_endpoint = '{{.APIEndpoint}}';</script> <script>window.api_endpoint = '{{.APIEndpoint}}';</script>
<link rel='stylesheet' href='/res/svelte/home_page.css'> <link rel='stylesheet' href='/res/svelte/home_page.css?v5'>
<script defer src='/res/svelte/home_page.js'></script> <script defer src='/res/svelte/home_page.js?v5'></script>
</head> </head>
<body> <body>
{{template "page_top" .}} {{template "page_top" .}}

View File

@@ -58,7 +58,6 @@ const upload_files = async (files) => {
id: "", id: "",
total_size: files[i].size, total_size: files[i].size,
loaded_size: 0, loaded_size: 0,
transfer_rate: 0,
on_finished: finish_upload, on_finished: finish_upload,
}) })
} }
@@ -98,7 +97,7 @@ const start_upload = () => {
state = "uploading" state = "uploading"
if (stats_interval === null) { if (stats_interval === null) {
stats_interval = setInterval(stats_update, 50) stats_interval = setInterval(stats_update, stats_interval_ms)
} }
} }
} }
@@ -109,12 +108,14 @@ const finish_upload = (file) => {
} }
let stats_interval = null let stats_interval = null
let stats_interval_ms = 500
let progress_bar_outer let progress_bar_outer
let progress_bar_inner let progress_bar_inner
let start_time = 0 let start_time = 0
let total_progress = 0 let total_progress = 0
let total_size = 0 let total_size = 0
let total_loaded = 0 let total_loaded = 0
let last_total_loaded = 0
let total_rate = 0 let total_rate = 0
let remaining_time = 0 let remaining_time = 0
const stats_update = () => { const stats_update = () => {
@@ -122,26 +123,31 @@ const stats_update = () => {
start_time = new Date().getTime() start_time = new Date().getTime()
} }
// Get total size of upload queue and size of finished uploads
total_size = 0 total_size = 0
total_loaded = 0 total_loaded = 0
total_rate = 0
for (let i = 0; i < upload_queue.length; i++) { for (let i = 0; i < upload_queue.length; i++) {
total_size += upload_queue[i].total_size total_size += upload_queue[i].total_size
total_loaded += upload_queue[i].loaded_size total_loaded += upload_queue[i].loaded_size
total_rate += upload_queue[i].transfer_rate
} }
total_progress = total_loaded / total_size total_progress = total_loaded / total_size
// Calculate ETA by estimating the total time and subtracting the elapsed time
let elapsed_time = new Date().getTime() - start_time let elapsed_time = new Date().getTime() - start_time
remaining_time = (elapsed_time/total_progress) - elapsed_time remaining_time = (elapsed_time/total_progress) - elapsed_time
// Calculate the rate by comparing the current progress with the last iteration
total_rate = (1000 / stats_interval_ms) * (total_loaded - last_total_loaded)
last_total_loaded = total_loaded
progress_bar_inner.style.width = (total_progress * 100) + "%" progress_bar_inner.style.width = (total_progress * 100) + "%"
} }
const stats_finished = () => { const stats_finished = () => {
start_time = 0 start_time = 0
total_loaded = total_size total_loaded = total_size
total_progress = 1
progress_bar_inner.style.width = "100%"
total_rate = 0 total_rate = 0
} }
@@ -408,10 +414,10 @@ const keydown = (e) => {
<span class="instruction_text">Wait for the files to finish uploading</span> <span class="instruction_text">Wait for the files to finish uploading</span>
<br/> <br/>
<div class="stats_box"> <div class="stats_box">
<div>Size: {formatDataVolume(total_size, 3)}</div> <div>Size {formatDataVolume(total_size, 3)}</div>
<div>Progress: {(total_progress*100).toPrecision(3)}%</div> <div>Progress {(total_progress*100).toPrecision(3)}%</div>
<div>ETA {formatDuration(remaining_time, 0)}</div> <div>ETA {formatDuration(remaining_time, 0)}</div>
<div>Rate: {formatDataVolume(total_rate, 3)}/s</div> <div>Rate {formatDataVolume(total_rate, 3)}/s</div>
</div> </div>
</div> </div>
</div> </div>
@@ -555,6 +561,8 @@ const keydown = (e) => {
background-color: var(--highlight_color); background-color: var(--highlight_color);
height: 100%; height: 100%;
width: 0; width: 0;
transition: width 0.5s;
transition-timing-function: linear;
} }
.social_buttons { .social_buttons {

View File

@@ -4,47 +4,45 @@ import { formatDataVolume, formatDuration} from "../util/Formatting.svelte"
export let job = {} export let job = {}
let file_button let file_button
let progress_bar
let tries = 0 let tries = 0
let start_time = 0 let start_time = 0
let remaining_time = 0 let remaining_time = 0
let statsInterval = null let stats_interval = null
let stats_interval_ms = 300
let progress = 0 let progress = 0
let last_progress_time = 0
let last_loaded_size = 0 let last_loaded_size = 0
let transfer_rate = 0
const on_progress = () => { const on_progress = () => {
if (job.loaded_size === 0 || job.total_size === 0) { if (job.loaded_size === 0 || job.total_size === 0) {
return return
} }
let now = new Date().getTime()
progress = job.loaded_size / job.total_size progress = job.loaded_size / job.total_size
let elapsed_time = now - start_time let elapsed_time = new Date().getTime() - start_time
remaining_time = (elapsed_time/progress) - elapsed_time remaining_time = (elapsed_time/progress) - elapsed_time
// Calculate transfer rate // Calculate transfer rate, apply smoothing by mixing it with the previous
if (last_progress_time != 0) { // rate ten to one
let new_rate = (1000 / (now - last_progress_time)) * (job.loaded_size - last_loaded_size) transfer_rate = Math.floor(
(transfer_rate * 0.9) +
(((1000 / stats_interval_ms) * (job.loaded_size - last_loaded_size)) * 0.1)
)
// Apply smoothing by mixing it with the previous number 10:1
job.transfer_rate = Math.floor((job.transfer_rate * 0.9) + (new_rate * 0.1))
}
last_progress_time = now
last_loaded_size = job.loaded_size last_loaded_size = job.loaded_size
file_button.style.background = 'linear-gradient(' + progress_bar.style.width = (progress * 100) + "%"
'to right, ' +
'var(--layer_3_color) 0%, ' +
'var(--highlight_color) ' + (progress * 100) + '%, ' +
'var(--layer_3_color) ' + ((progress * 100) + 1) + '%)'
} }
let href = null let href = null
let target = null let target = null
const on_success = (resp) => { const on_success = (resp) => {
clearInterval(statsInterval) clearInterval(stats_interval)
job.transfer_rate = 0 stats_interval = null
transfer_rate = 0
job.loaded_size = job.total_size
job.file = null // Delete reference to file to free memory
job.id = resp.id job.id = resp.id
job.status = "finished" job.status = "finished"
@@ -56,27 +54,31 @@ const on_success = (resp) => {
target = "_blank" target = "_blank"
file_button.style.background = 'var(--layer_3_color)' file_button.style.background = 'var(--layer_3_color)'
progress_bar.style.width = "100%"
} }
let error_id = "" let error_id = ""
let error_reason = "" let error_reason = ""
const on_failure = (status, message) => { const on_failure = (status, message) => {
clearInterval(statsInterval) clearInterval(stats_interval)
job.transfer_rate = 0 stats_interval = null
transfer_rate = 0
job.loaded_size = job.total_size job.loaded_size = job.total_size
job.file = null // Delete reference to file to free memory
error_id = status error_id = status
error_reason = message error_reason = message
job.status = "error" job.status = "error"
file_button.style.background = 'var(--danger_color)' file_button.style.background = 'var(--danger_color)'
file_button.style.color = 'var(--highlight_text_color)' file_button.style.color = 'var(--highlight_text_color)'
progress_bar.style.width = "0"
job.on_finished(job) job.on_finished(job)
} }
export const start = () => { export const start = () => {
start_time = new Date().getTime() start_time = new Date().getTime()
statsInterval = setInterval(on_progress, 50) // 20 FPS, plenty for stats stats_interval = setInterval(on_progress, stats_interval_ms)
let form = new FormData(); let form = new FormData();
form.append('file', job.file, job.name); form.append('file', job.file, job.name);
@@ -156,6 +158,7 @@ const add_upload_history = id => {
</script> </script>
<a bind:this={file_button} class="upload_task" {href} {target}> <a bind:this={file_button} class="upload_task" {href} {target}>
<div class="top_half">
<div class="thumbnail"> <div class="thumbnail">
{#if job.status === "queued"} {#if job.status === "queued"}
<i class="icon">cloud_queue</i> <i class="icon">cloud_queue</i>
@@ -186,7 +189,7 @@ const add_upload_history = id => {
ETA {formatDuration(remaining_time, 0)} ETA {formatDuration(remaining_time, 0)}
</div> </div>
<div class="stat"> <div class="stat">
{formatDataVolume(job.transfer_rate, 3)}/s {formatDataVolume(transfer_rate, 3)}/s
</div> </div>
{:else if job.status === "finished"} {:else if job.status === "finished"}
<span class="file_link"> <span class="file_link">
@@ -197,6 +200,10 @@ const add_upload_history = id => {
{/if} {/if}
</div> </div>
</div> </div>
</div>
<div class="progress">
<div bind:this={progress_bar} class="progress_bar"></div>
</div>
</a> </a>
<style> <style>
@@ -204,9 +211,9 @@ const add_upload_history = id => {
.upload_task{ .upload_task{
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
width: 420px; width: 440px;
max-width: 90%; max-width: 95%;
height: 3.8em; height: 4em;
margin: 10px; margin: 10px;
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
@@ -218,7 +225,7 @@ const add_upload_history = id => {
text-align: left; text-align: left;
line-height: 1.2em; line-height: 1.2em;
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: column;
transition: box-shadow 0.3s, opacity 2s; transition: box-shadow 0.3s, opacity 2s;
white-space: normal; white-space: normal;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -226,12 +233,18 @@ const add_upload_history = id => {
vertical-align: top; vertical-align: top;
cursor: pointer; cursor: pointer;
} }
.top_half {
flex: 1 1 auto;
display: flex;
flex-direction: row;
overflow: hidden;
}
.upload_task:hover { .upload_task:hover {
box-shadow: 0 0 2px 2px var(--highlight_color), inset 0 0 1px 1px var(--highlight_color); box-shadow: 0 0 2px 2px var(--highlight_color), inset 0 0 1px 1px var(--highlight_color);
text-decoration: none; text-decoration: none;
} }
.upload_task > .thumbnail { .thumbnail {
display: flex; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
width: 3.8em; width: 3.8em;
@@ -239,22 +252,22 @@ const add_upload_history = id => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.upload_task > .thumbnail > img { .thumbnail > img {
width: 100%; width: 100%;
} }
.upload_task > .thumbnail > i { .thumbnail > i {
font-size: 3em; font-size: 3em;
} }
.upload_task > .queue_body { .queue_body {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.upload_task > .queue_body > .title { .queue_body > .title {
flex: 1 1 auto; flex: 1 1 auto;
overflow: hidden; overflow: hidden;
} }
.upload_task > .queue_body > .stats { .queue_body > .stats {
flex: 0 0 auto; flex: 0 0 auto;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@@ -264,11 +277,21 @@ const add_upload_history = id => {
font-family: sans-serif, monospace; font-family: sans-serif, monospace;
font-size: 0.9em; font-size: 0.9em;
} }
.upload_task > .queue_body > .stats > .stat { .queue_body > .stats > .stat {
flex: 0 1 100%; flex: 0 1 100%;
} }
.file_link{ .file_link{
color: var(--highlight_color); color: var(--highlight_color);
} }
.progress {
flex: 0 0 auto;
height: 2px;
}
.progress_bar {
background-color: var(--highlight_color);
height: 100%;
width: 0;
transition: width 0.3s;
transition-timing-function: linear;
}
</style> </style>