From cc00e585618a8dd29574847c97a4ccdac6c7318f Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen <sebastiaan.de.schaetzen@gmail.com> Date: Tue, 17 Jun 2025 11:47:50 +0200 Subject: [PATCH] Refactor loader functionality to improve user experience during video loading --- static/index.html | 65 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/static/index.html b/static/index.html index 27e489a..345e69b 100644 --- a/static/index.html +++ b/static/index.html @@ -16,6 +16,11 @@ } .loader { + position: fixed; /* Changed for global overlay */ + left: 50%; + top: 50%; + transform: translate(-50%, -50%); /* Center on screen */ + z-index: 10001; /* Above video overlay */ border: 1.5vw solid #333; border-top: 1.5vw solid #3498db; border-bottom: 1.5vw solid #3498db; @@ -164,11 +169,18 @@ } </style> <script> - function hideLoader() { + function hideSpinner() { // Was hideLoader, now only hides spinner $(".loader").hide(); - $(".video-container").css("display", "flex"); } + function showSpinner() { // Was showLoader + $(".loader").show(); + } + + function showVideoContainer() { + $(".video-container").css("display", "flex"); + } + let currentVideo = null; let videoElement = null; let overlayContainer = null; @@ -293,18 +305,30 @@ playPauseButton = customControls.find("#custom-play-pause-button"); seekBar = customControls.find("#custom-seek-bar"); + // Spinner is visible by default (CSS). Video container is hidden (CSS). // Pre-set all thumbnails to a placeholder state - $(".video-thumbnail").attr("src", "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 16 9'%3E%3C/svg%3E"); + $(".video-thumbnail").attr("src", "data:image/svg+xml,%3Csvg xmlns=\\\'http://www.w3.org/2000/svg\\\' width=\\\'100%25\\\' height=\\\'100%25\\\' viewBox=\\\'0 0 16 9\\\'%3E%3C/svg%3E"); $.getJSON("/api/homepage", function(data) { currentVideo = data.currentVideo; $("#current-thumb").attr("src", currentVideo.thumbnail); - hideLoader(); + // Consider populating prev-thumb and next-thumb here if data provides them + + hideSpinner(); + showVideoContainer(); + // FOCUS: Set initial focus on the main screen if ($(".video-container").is(":visible") && $('#play-button').length) { $('#play-button').focus(); } - }) + }).fail(function(jqXHR, textStatus, errorThrown) { + console.error("Failed to load homepage data:", textStatus, errorThrown); + hideSpinner(); + // Display a user-friendly error message + if (!$('#init-error-msg').length) { // Prevent multiple error messages + $('body').append('<div id="init-error-msg" style="color:white; text-align:center; padding:20px; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); background-color:rgba(0,0,0,0.8); border-radius:8px; z-index: 10002;">Failed to load content. Please try again later.</div>'); + } + }); // Attach event listeners that can be set up once for static controls if (playPauseButton) playPauseButton.click(handlePlayPauseClick); @@ -314,7 +338,30 @@ $("#play-button").click(function() { if (currentVideo && currentVideo.url && videoElement && overlayContainer) { - // Set video source and load + showSpinner(); + + // Clear previous handlers and set new ones for this specific load attempt + videoElement.oncanplaythrough = null; + videoElement.onerror = null; + + videoElement.oncanplaythrough = function() { + hideSpinner(); + videoElement.oncanplaythrough = null; // Clean up handler + videoElement.onerror = null; // Clean up handler + videoElement.play().catch(err => { + console.error("Error attempting to play video:", err); + exitVideoPlayback(); // Exit overlay on play error + }); + }; + + videoElement.onerror = function() { + console.error("Error loading video."); + hideSpinner(); + videoElement.oncanplaythrough = null; // Clean up handler + videoElement.onerror = null; // Clean up handler + exitVideoPlayback(); // Exit overlay on load error + }; + videoElement.src = currentVideo.url; videoElement.load(); @@ -341,7 +388,11 @@ playPauseButton.focus(); } - videoElement.play().catch(err => console.error("Error attempting to play video:", err)); + // The oncanplaythrough is now set before load() + // videoElement.oncanplaythrough = function() { + // hideSpinner(); // Changed from hideLoader() + // videoElement.play().catch(err => console.error("Error attempting to play video:", err)); + // } } });