Stop resetting lesson progress on view, and add Notes Hub search
view_lesson() called update_lesson_progress() with no arguments on every page load, which defaults completed=False and progress_seconds=0 and silently overwrote whatever was already saved - just opening an already-watched lesson reset its progress/completed state unless the client happened to report real values within the next 15 seconds. Replaced with touch_lesson_accessed(), which only bumps last_accessed. Also fixes the "Resume from Xs" feature this fed into: it read a value that was never populated on this route, and even when given a real one, checked activeMedia.duration synchronously before metadata had loaded, so it silently never applied. Now waits for loadedmetadata (or resolves immediately if already available) and defers to an explicit note-timestamp jump (?t=) when both are present. Notes Hub gets a live search box filtering by note text, lesson title, or course name (client-side, no reload), with a "no notes match" state - useful now that a single category folder can hold dozens of courses' worth of timestamped notes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+19
-11
@@ -912,12 +912,27 @@
|
||||
|
||||
renderNotes();
|
||||
|
||||
if (activeMedia && INITIAL_SEEK_SECONDS !== null && INITIAL_SEEK_SECONDS !== undefined) {
|
||||
const doInitialSeek = function() { activeMedia.currentTime = INITIAL_SEEK_SECONDS; };
|
||||
// Seek once metadata is available (activeMedia.duration is NaN
|
||||
// before that, so doing this synchronously on script load - as
|
||||
// this used to - silently never applied). An explicit jump to
|
||||
// a note's timestamp (?t=, see INITIAL_SEEK_SECONDS) takes
|
||||
// priority over resuming general playback progress.
|
||||
const savedProgressSeconds = {{ lesson_progress_seconds|default(0) }};
|
||||
|
||||
function applyInitialSeek() {
|
||||
if (INITIAL_SEEK_SECONDS !== null && INITIAL_SEEK_SECONDS !== undefined) {
|
||||
activeMedia.currentTime = INITIAL_SEEK_SECONDS;
|
||||
} else if (savedProgressSeconds > 0 && savedProgressSeconds < activeMedia.duration - 30) {
|
||||
activeMedia.currentTime = savedProgressSeconds;
|
||||
showNotification(`Resumed from ${Math.floor(savedProgressSeconds / 60)}:${String(Math.floor(savedProgressSeconds % 60)).padStart(2, '0')}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeMedia) {
|
||||
if (activeMedia.readyState >= 1) {
|
||||
doInitialSeek();
|
||||
applyInitialSeek();
|
||||
} else {
|
||||
activeMedia.addEventListener('loadedmetadata', doInitialSeek, { once: true });
|
||||
activeMedia.addEventListener('loadedmetadata', applyInitialSeek, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,13 +1062,6 @@
|
||||
saveProgress(activeMedia.currentTime, true);
|
||||
markAsCompleted();
|
||||
});
|
||||
|
||||
// Resume from saved position
|
||||
const savedProgress = {{ lesson.progress_seconds|default(0) }};
|
||||
if (savedProgress > 0 && savedProgress < activeMedia.duration - 30) {
|
||||
activeMedia.currentTime = savedProgress;
|
||||
showNotification(`Resumed from ${Math.floor(savedProgress / 60)}:${String(Math.floor(savedProgress % 60)).padStart(2, '0')}`);
|
||||
}
|
||||
}
|
||||
|
||||
function saveProgress(progressSeconds, completed = false) {
|
||||
|
||||
Reference in New Issue
Block a user