Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 41 additions & 16 deletions propresenter_notes/static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ let selectedLibraryId = '';
let selectedSlideIndex = 0;
let selectedCache = null;
let changeTimer = null;
let pendingSlideTrigger = null;
let slideTriggerInFlight = false;
let touchStart = null;

const selectionStorageKey = 'propresenter-notes-selection';
Expand Down Expand Up @@ -346,9 +348,9 @@ function renderSlides() {
button.appendChild(placeholder);
}

button.addEventListener('click', async () => {
await triggerSlide(slide.index);
button.addEventListener('click', () => {
showSlide(slide.index);
queueSlideTrigger(slide.index);
});
el.thumbnailStrip.appendChild(button);
});
Expand Down Expand Up @@ -422,13 +424,38 @@ function startChangeWatcher() {
changeTimer = setInterval(checkForPresentationChanges, 5000);
}

async function triggerSlide(index) {
if (!selected) return false;
function queueSlideTrigger(index) {
const presentationId = selectedPresentationId();
if (!presentationId) return;

pendingSlideTrigger = { presentationId, index };
if (!slideTriggerInFlight) {
void flushSlideTriggerQueue();
}
}

async function flushSlideTriggerQueue() {
slideTriggerInFlight = true;
try {
while (pendingSlideTrigger) {
const trigger = pendingSlideTrigger;
pendingSlideTrigger = null;
await sendSlideTrigger(trigger);
}
} finally {
slideTriggerInFlight = false;
if (pendingSlideTrigger) {
void flushSlideTriggerQueue();
}
}
}

async function sendSlideTrigger({ presentationId, index }) {
try {
await request('/api/trigger/slide', {
method: 'POST',
body: JSON.stringify({
presentationId: selectedPresentationId(),
presentationId,
index
})
});
Expand All @@ -440,19 +467,17 @@ async function triggerSlide(index) {
}
}

async function trigger(direction) {
function trigger(direction) {
if (!selectedCache?.slides?.length) return;

el.previous.disabled = true;
el.next.disabled = true;
try {
const delta = direction === 'next' ? 1 : -1;
const nextIndex = Math.max(0, Math.min(selectedSlideIndex + delta, selectedCache.slides.length - 1));
await triggerSlide(nextIndex);
showSlide(nextIndex);
} finally {
updateNavState();
}
const delta = direction === 'next' ? 1 : -1;
const nextIndex = Math.max(0, Math.min(selectedSlideIndex + delta, selectedCache.slides.length - 1));
if (nextIndex === selectedSlideIndex) return;

// Keep speaker notes responsive even when the ProPresenter API is slow or unavailable.
// The API request is queued in the background and coalesced to the latest requested slide.
showSlide(nextIndex);
queueSlideTrigger(nextIndex);
}

function handleTouchStart(event) {
Expand Down
Loading