Compare commits
2 commits
1026ed09a7
...
38451514c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38451514c2 | ||
|
|
7392bbcdcc |
2 changed files with 12 additions and 25 deletions
|
|
@ -27,11 +27,13 @@ def book_list(request):
|
||||||
b['uploaded_at'] = b['uploaded_at'].isoformat()
|
b['uploaded_at'] = b['uploaded_at'].isoformat()
|
||||||
# Include saved scroll_fraction for each book
|
# Include saved scroll_fraction for each book
|
||||||
progress_map = {
|
progress_map = {
|
||||||
p.book_id: p.scroll_fraction
|
p.book_id: (p.scroll_fraction, p.updated_at)
|
||||||
for p in EBookProgress.objects.filter(user=request.user)
|
for p in EBookProgress.objects.filter(user=request.user)
|
||||||
}
|
}
|
||||||
for b in books:
|
for b in books:
|
||||||
b['scroll_fraction'] = progress_map.get(b['id'], 0.0)
|
prog = progress_map.get(b['id'])
|
||||||
|
b['scroll_fraction'] = prog[0] if prog else 0.0
|
||||||
|
b['last_read'] = prog[1].isoformat() if prog else None
|
||||||
return JsonResponse(books, safe=False)
|
return JsonResponse(books, safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2644,12 +2644,18 @@ async function loadBookList() {
|
||||||
const metaBuf = await decryptBytes(key, b.meta_iv, b.meta_ct);
|
const metaBuf = await decryptBytes(key, b.meta_iv, b.meta_ct);
|
||||||
const meta = JSON.parse(new TextDecoder().decode(metaBuf));
|
const meta = JSON.parse(new TextDecoder().decode(metaBuf));
|
||||||
bookMetaCache[b.id] = {title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub'};
|
bookMetaCache[b.id] = {title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub'};
|
||||||
decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: true});
|
decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, last_read: b.last_read || null, keyOk: true});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
bookMetaCache[b.id] = {title: `Book #${b.id}`, author: '', type: 'epub'};
|
bookMetaCache[b.id] = {title: `Book #${b.id}`, author: '', type: 'epub'};
|
||||||
decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: false});
|
decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, last_read: b.last_read || null, keyOk: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
decrypted.sort((a, b) => {
|
||||||
|
if (a.last_read && b.last_read) return b.last_read.localeCompare(a.last_read);
|
||||||
|
if (a.last_read) return -1;
|
||||||
|
if (b.last_read) return 1;
|
||||||
|
return b.uploaded_at.localeCompare(a.uploaded_at);
|
||||||
|
});
|
||||||
renderBookList(decrypted);
|
renderBookList(decrypted);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (listEl) listEl.innerHTML = `<p class="muted">Error loading books: ${e.message}</p>`;
|
if (listEl) listEl.innerHTML = `<p class="muted">Error loading books: ${e.message}</p>`;
|
||||||
|
|
@ -2959,16 +2965,6 @@ async function openBook(bookId) {
|
||||||
// Apply reader settings (theme, font size, etc.)
|
// Apply reader settings (theme, font size, etc.)
|
||||||
applyReaderSettings(isPdfBook);
|
applyReaderSettings(isPdfBook);
|
||||||
|
|
||||||
// Enable PDF paginated mode if configured (auto on mobile)
|
|
||||||
if (isPdfBook && readerSettings.pdfPaginated) {
|
|
||||||
enterPdfPaginatedMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wire highlight selection listener for EPUB
|
|
||||||
if (!isPdfBook) {
|
|
||||||
contentEl.addEventListener('mouseup', handleReaderSelection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swipe for PDF paginated
|
// Swipe for PDF paginated
|
||||||
contentEl.addEventListener('touchstart', e => { _touchStartX = e.touches[0].clientX; }, {passive: true});
|
contentEl.addEventListener('touchstart', e => { _touchStartX = e.touches[0].clientX; }, {passive: true});
|
||||||
contentEl.addEventListener('touchend', e => {
|
contentEl.addEventListener('touchend', e => {
|
||||||
|
|
@ -3381,7 +3377,6 @@ function toggleSettingsPanel() {
|
||||||
panel.innerHTML = `
|
panel.innerHTML = `
|
||||||
<label>Zoom <input type="range" id="rs-zoom" min="50" max="200" step="10" value="${readerSettings.pdfZoom}"> <span id="rs-zoom-val">${readerSettings.pdfZoom}%</span></label>
|
<label>Zoom <input type="range" id="rs-zoom" min="50" max="200" step="10" value="${readerSettings.pdfZoom}"> <span id="rs-zoom-val">${readerSettings.pdfZoom}%</span></label>
|
||||||
<button class="btn btn-sm ${readerSettings.pdfInverted ? 'active' : ''}" id="rs-invert">Invert</button>
|
<button class="btn btn-sm ${readerSettings.pdfInverted ? 'active' : ''}" id="rs-invert">Invert</button>
|
||||||
<button class="btn btn-sm ${readerSettings.pdfPaginated ? 'active' : ''}" id="rs-paginated">Paginated</button>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3453,16 +3448,6 @@ function toggleSettingsPanel() {
|
||||||
saveReaderSettings();
|
saveReaderSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
panel.querySelector('#rs-paginated').addEventListener('click', function () {
|
|
||||||
readerSettings.pdfPaginated = !readerSettings.pdfPaginated;
|
|
||||||
this.classList.toggle('active', readerSettings.pdfPaginated);
|
|
||||||
saveReaderSettings();
|
|
||||||
if (readerSettings.pdfPaginated) {
|
|
||||||
enterPdfPaginatedMode();
|
|
||||||
} else {
|
|
||||||
exitPdfPaginatedMode();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue