From a0ab3547639121a47bfc81404771a3711a203fa5 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Wed, 19 Aug 2026 20:25:10 -0400 Subject: [PATCH] Paint applied highlights natively (yellow) and immediately; suppress echo color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two rendering observations from live use: - Synced highlights rendered grey while device-native ones are yellow: KOReader natively stamps view.highlight.saved_color ("yellow" on color screens) onto every new highlight; a nil color takes the darkenRect path (grey). Applied entries now carry the device's own saved_color, so they look exactly like native ones. - They only appeared after a restart: ReaderView caches each rendered page's highlight boxes and only invalidates the cache on AnnotationsModified — a plain setDirty repaints from the stale cache. applyServerAnnotations now dispatches AnnotationsModified with a non-table payload (clears the whole cache) before setDirty. Echo safety for the new default color: an applied entry's yellow is the device default, not user intent — pushing it back would clobber the web color. collectAnnotations suppresses the color for entries we applied (bookhoard_dedup_key set) that the user has not modified since (datetime_updated, which KOReader sets on any edit); edited entries push their color and the server lets the edit win. Verified in the harness: applied entry gets color=yellow; un-edited echo carries no color; an edited (datetime_updated + green) echo sends green and the web row updates; dedup keys round-trip throughout. --- main.lua | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/main.lua b/main.lua index fb3bf43..ce6a066 100644 --- a/main.lua +++ b/main.lua @@ -876,6 +876,20 @@ function Bookhoard:collectAnnotations() return p or "" end + local function echoColor(bm) + -- Color the device can vouch for as user intent: + -- - entries we applied ourselves carry the device DEFAULT color + -- (set at apply time); pushing it back would clobber the web + -- color. Suppress it unless the user has edited the entry since + -- (datetime_updated — set by KOReader on any modification). + -- - device-native entries carry a user-chosen (or default) color; + -- those push their color as before. + if bm.bookhoard_dedup_key and not bm.datetime_updated then + return nil + end + return bm.color + end + for _, bm in ipairs(entries) do local sel_text, user_note if model == "v2" then @@ -936,8 +950,9 @@ function Bookhoard:collectAnnotations() table.insert(notes, entry) elseif has_text then entry.type = "highlight" - if bm.color then - entry.color = bm.color + local ec = echoColor(bm) + if ec then + entry.color = ec end table.insert(highlights, entry) else @@ -1325,10 +1340,15 @@ function Bookhoard:applyServerAnnotations(annotations) entry.drawer = "lighten" entry.text = srv_text if srv_notes ~= "" then entry.note = srv_notes end - -- No color imposed: devices render their own default and - -- cannot round-trip web colors; the web color only changes - -- when the highlight is edited here (the edit sets a device - -- color, which syncs back by name). + -- Match the device's native highlight look exactly: native + -- highlights carry view.highlight.saved_color ("yellow" on + -- color screens); a nil color renders grey (darkenRect). + -- Synced entries still never push this color back (see + -- collectAnnotations) — the web color only changes when the + -- highlight is edited here. + local default_color = (self.ui.view and self.ui.view.highlight + and self.ui.view.highlight.saved_color) or "yellow" + entry.color = default_color else if srv_text ~= "" then entry.note = srv_text end -- bookmark label end @@ -1426,8 +1446,12 @@ function Bookhoard:applyServerAnnotations(annotations) if self.ui.saveSettings then self.ui:saveSettings() end - -- ReaderView paints annotations from the model on each repaint; - -- request one so applied highlights appear immediately. + -- ReaderView caches each rendered page's highlight boxes and only + -- invalidates them on AnnotationsModified — without this, applied + -- annotations don't paint until restart despite the repaint. + -- A non-table payload clears the whole cache (per-item payloads + -- only remove the pages of the listed items). + self.ui:handleEvent(Event:new("AnnotationsModified", nil)) if self.ui.dialog then UIManager:setDirty(self.ui.dialog, "ui") end