Files
readest/apps
Huang Xin ab2def32dd fix(koplugin): stop sync from wiping cloud book fields + Library polish (#4166)
* fix(koplugin): pull before push so sync doesn't wipe cloud book fields, closes #4138

The Library sync pushed a touched book row before pulling, so a row
still missing the cloud's uploaded_at / metadata / group_id (e.g. one
created by lightScan, not yet merged from a cloud pull) was sent with
those fields nil. The server's transformBookToDB explicit-nulls
uploaded_at and metadata for any field absent from the wire payload,
wiping the cloud copy — after which every device that pulled lost the
book's upload state.

syncBooks("both") now pulls first, then pushes, and takes a before_push
callback. syncBooksLibrary passes touchOpenBook through it so the
open book's updated_at bump lands after the pull has refreshed the
local row, letting the push carry the preserved cloud fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(koplugin): hide Library books with neither an uploaded nor a local file

The Library showed any row with cloud_present = 1, but a bare cloud
*record* whose file was never uploaded (uploaded_at NULL) has no cover
and can't be opened — showing it is meaningless. Tighten the visibility
predicate to (uploaded_at IS NOT NULL OR local_present = 1) across
listBooks, getGroups, listBookshelfGroups and listBooksInGroup.

This mirrors Readest, which only adds a synced book to the library when
uploadedAt is set and keeps locally-imported books that carry a
downloadedAt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(koplugin): close the Library widget when opening a book

Opening a book from the Library called ReaderUI:showReader without
closing the Library Menu, so it stayed in the UIManager widget stack
with M._menu still set. A later background M.refresh() — a cloud-sync
or cover-download completion — then repainted that ghost Library over
the reader, making it flash on screen for a few seconds.

Add M.close(); route the title-bar X, M.reopen() and both handleTap
book-open paths through it. A wrapped onCloseWidget clears M._menu on
every close path, so M.refresh() no-ops once the Menu is gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:05:49 +02:00
..