From 0619a99aba884d39b9d2ce99dd58e934d6f7dc44 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sun, 17 Nov 2024 13:05:01 +1100 Subject: [PATCH] Update image uploading logic --- data/db.sqlite3 | Bin 241664 -> 262144 bytes links/templates/links/collection_detail.html | 41 ++++++-- .../templates/links/collection_slideshow.html | 99 +++++++++++++----- 3 files changed, 103 insertions(+), 37 deletions(-) diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 3230a491d0fa3700cb34416bf4e759afc37ba995..5e07870cf66bc06aac8ce642e63878b34ef06234 100644 GIT binary patch delta 17624 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 DcJnF4 delta 373 zcmZo@5NLS7H$jSx=@kP5gY`rOJ0_-AjR~y@j9U|!miS9>@ntda_48%%Z|9%HpUdyT zugv$4? zl45SAo0MvqsB3CrnVOhrWNBz%YN!v@@Oc-rvXYseiG``TiG`7Yk%_LMp{}91f`Orx zk*SptM8?7d;{J%;%qv(}fI;$oa-zUz87}@i4A7wX$F~I-93G$m;kyY85@kqGWZ5y# PP$cAZ_U+2{%y$a_c-&@8 diff --git a/links/templates/links/collection_detail.html b/links/templates/links/collection_detail.html index 360cb16..24a2bae 100644 --- a/links/templates/links/collection_detail.html +++ b/links/templates/links/collection_detail.html @@ -166,8 +166,10 @@ const dropzone = new Dropzone("#uploadForm", { }, paramName: "file", acceptedFiles: 'image/*', - parallelUploads: 4, + parallelUploads: 5, maxFilesize: 10, + uploadMultiple: false, // Process one file at a time + autoProcessQueue: true, dictDefaultMessage: `
@@ -180,18 +182,41 @@ const dropzone = new Dropzone("#uploadForm", {
`, init: function() { - this.on("success", function(file, response) { - console.log("Upload successful:", response); + let totalFiles = 0; + let completedFiles = 0; + + this.on("addedfile", function(file) { + totalFiles++; + console.log(`Added file: ${file.name}. Total files: ${totalFiles}`); }); + + this.on("success", function(file, response) { + completedFiles++; + console.log(`Upload successful: ${file.name}. Completed: ${completedFiles}/${totalFiles}`); + file.previewElement.classList.add('dz-success'); + }); + this.on("error", function(file, errorMessage) { - console.error("Upload error:", errorMessage); + console.error(`Upload error for ${file.name}:`, errorMessage); + completedFiles++; + file.previewElement.classList.add('dz-error'); alert(typeof errorMessage === 'string' ? errorMessage : errorMessage.error || 'Upload failed'); }); + this.on("queuecomplete", function() { - console.log("All uploads completed"); - setTimeout(() => { - location.reload(); - }, 1000); + console.log("Queue complete. All files processed."); + if (completedFiles === totalFiles) { + console.log("All files uploaded successfully. Reloading page..."); + setTimeout(() => { + location.reload(); + }, 1000); + } + }); + + // Reset counters when queue is cleared + this.on("reset", function() { + totalFiles = 0; + completedFiles = 0; }); } }); diff --git a/links/templates/links/collection_slideshow.html b/links/templates/links/collection_slideshow.html index 20ce6dd..b405af3 100644 --- a/links/templates/links/collection_slideshow.html +++ b/links/templates/links/collection_slideshow.html @@ -68,20 +68,43 @@ .control-button:hover { background: rgba(255,255,255,0.2); } - .progress-bar { + .progress-circle { position: fixed; - top: 0; - left: 0; - height: 2px; - background: #3b82f6; - transition: width 0.1s linear; + bottom: 2rem; + right: 2rem; + width: 32px; + height: 32px; + z-index: 50; + opacity: 0.8; + } + .progress-circle-bg { + fill: none; + stroke: rgba(255, 255, 255, 0.2); + stroke-width: 2.5; + } + .progress-circle-path { + fill: none; + stroke: #3b82f6; + stroke-width: 2.5; + stroke-linecap: round; + transform: rotate(-90deg); + transform-origin: center; } {% endblock %} {% block content %}
-
+
+ + + + +
{% for image in collection.images.all %}
@@ -124,10 +147,11 @@ let currentSlide = 0; const slides = document.querySelectorAll('.slide'); const totalSlides = slides.length; let slideInterval = null; +let progressInterval = null; let isPlaying = true; const INTERVAL_TIME = 5000; // 5 seconds -let progressWidth = 0; -let progressInterval = null; +let startTime = null; +let animationFrame = null; function showSlide(index) { slides.forEach(slide => slide.classList.remove('active')); @@ -162,40 +186,55 @@ function togglePlayPause() { function startSlideshow() { stopSlideshow(); + startTime = Date.now(); slideInterval = setInterval(nextSlide, INTERVAL_TIME); - startProgress(); + updateProgress(); } function stopSlideshow() { clearInterval(slideInterval); - clearInterval(progressInterval); - progressWidth = 0; - updateProgressBar(); + if (animationFrame) { + cancelAnimationFrame(animationFrame); + animationFrame = null; + } + startTime = null; } function exitSlideshow() { window.location.href = '{% url "collection-detail" collection.pk %}'; } -function startProgress() { - progressWidth = 0; - const progressStep = 100 / (INTERVAL_TIME / 10); // Update every 10ms - progressInterval = setInterval(() => { - progressWidth = Math.min(100, progressWidth + progressStep); - updateProgressBar(); - }, 10); +function updateProgress() { + if (!startTime || !isPlaying) return; + + const elapsed = Date.now() - startTime; + const progress = Math.min(100, (elapsed / INTERVAL_TIME) * 100); + + const circle = document.querySelector('.progress-circle-path'); + + // Calculate the circumference of the circle + const radius = 16; + const circumference = 2 * Math.PI * radius; + + // Calculate the dash offset based on progress + const dashOffset = circumference * (1 - progress / 100); + + // Update the circle + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = dashOffset; + + // Request next frame + animationFrame = requestAnimationFrame(updateProgress); } function resetProgress() { - progressWidth = 0; - updateProgressBar(); + startTime = Date.now(); + if (animationFrame) { + cancelAnimationFrame(animationFrame); + } if (isPlaying) { - startProgress(); + updateProgress(); } -} - -function updateProgressBar() { - document.getElementById('progressBar').style.width = `${progressWidth}%`; } // Keyboard controls @@ -216,7 +255,9 @@ document.addEventListener('keydown', (e) => { } }); -// Start slideshow -startSlideshow(); +// Start slideshow when page loads +document.addEventListener('DOMContentLoaded', () => { + startSlideshow(); +}); {% endblock %}