Update readerannotation.lua

reviewable/pr11563/r5
hius07 2 months ago committed by GitHub
parent cbd30e456c
commit 3a9b77b6cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,11 +4,25 @@ local ReaderAnnotation = WidgetContainer:extend{
annotations = nil, annotations = nil,
} }
-- build, read, save
function ReaderAnnotation:buildAnnotation(bm, highlights, update_pageno) function ReaderAnnotation:buildAnnotation(bm, highlights, update_pageno)
-- bm - corresponding bookmark, highlights - all highlights -- bm - corresponding bookmark, highlights - all highlights
local note = bm.text
if note == "" then
note = nil
end
local chapter = bm.chapter
local hl, pageno = self:getHighlightByDatetime(highlights, bm.datetime) local hl, pageno = self:getHighlightByDatetime(highlights, bm.datetime)
if update_pageno then -- cannot be done in onReadSettings() if update_pageno then
pageno = self.ui.paging and bm.page or self.document:getPageFromXPointer(bm.page) if note and self.ui.bookmark:isBookmarkAutoText(bm) then
note = nil
end
if chapter == nil then
local pn_or_xp = (self.ui.rolling and bm.pos0) and bm.pos0 or bm.page
chapter = self.ui.toc:getTocTitleByPage(pn_or_xp)
end
pageno = self.ui.bookmark:getBookmarkPageString(bm.page)
end end
if not hl then -- page bookmark or orphaned bookmark if not hl then -- page bookmark or orphaned bookmark
hl = {} hl = {}
@ -24,7 +38,6 @@ function ReaderAnnotation:buildAnnotation(bm, highlights, update_pageno)
end end
end end
end end
local note = bm.text ~= "" and bm.text or nil
if self.ui.paging then if self.ui.paging then
-- old single-page reflow highlights do not have page in position -- old single-page reflow highlights do not have page in position
if not bm.pos0.page then if not bm.pos0.page then
@ -39,7 +52,7 @@ function ReaderAnnotation:buildAnnotation(bm, highlights, update_pageno)
text = bm.notes, -- highlighted text, editable text = bm.notes, -- highlighted text, editable
text_edited = hl.edited, -- true if highlighted text has been edited text_edited = hl.edited, -- true if highlighted text has been edited
note = note, -- user's note, editable note = note, -- user's note, editable
chapter = bm.chapter, -- book chapter title chapter = chapter, -- book chapter title
pageno = pageno, -- book page number pageno = pageno, -- book page number
page = bm.page, -- highlight location, xPointer or number (pdf) page = bm.page, -- highlight location, xPointer or number (pdf)
pos0 = bm.pos0, -- highlight start position, xPointer (== page) or table (pdf) pos0 = bm.pos0, -- highlight start position, xPointer (== page) or table (pdf)
@ -49,35 +62,6 @@ function ReaderAnnotation:buildAnnotation(bm, highlights, update_pageno)
} }
end end
function ReaderAnnotation.buildBookmark(an)
return {
datetime = an.datetime,
highlighted = an.drawer and true or nil,
notes = an.text,
text = an.note,
chapter = an.chapter,
page = an.page,
pos0 = an.pos0,
pos1 = an.pos1,
}
end
function ReaderAnnotation.buildHighlight(an)
return {
datetime = an.datetime,
drawer = an.drawer,
color = an.color,
text = an.text,
edited = an.text_edited,
chapter = an.chapter,
page = an.page,
pos0 = an.pos0,
pos1 = an.pos1,
pboxes = an.pboxes,
ext = an.ext,
}
end
function ReaderAnnotation:getHighlightByDatetime(highlights, datetime) function ReaderAnnotation:getHighlightByDatetime(highlights, datetime)
for pageno, page_highlights in pairs(highlights) do for pageno, page_highlights in pairs(highlights) do
for i, highlight in ipairs(page_highlights) do for i, highlight in ipairs(page_highlights) do
@ -93,31 +77,25 @@ function ReaderAnnotation:getAnnotationsFromBookmarksHighlights(bookmarks, highl
for i = #bookmarks, 1, -1 do for i = #bookmarks, 1, -1 do
table.insert(annotations, self:buildAnnotation(bookmarks[i], highlights, update_pageno)) table.insert(annotations, self:buildAnnotation(bookmarks[i], highlights, update_pageno))
end end
return annotations if #annotations > 1 then
end local sort_func = function(a, b)
if self.ui.rolling then
function ReaderAnnotation:getBookmarksHighlightsFromAnnotations(annotations) return self:isItemInPositionOrderRolling(a, b)
local bookmarks, highlights = {}, {} else
for i = #annotations, 1, -1 do return self:isItemInPositionOrderPaging(a, b)
local an = annotations[i]
table.insert(bookmarks, self.buildBookmark(an))
if an.drawer then
if highlights[an.pageno] == nil then
highlights[an.pageno] = {}
end end
table.insert(highlights[an.pageno], self.buildHighlight(an))
end end
table.sort(annotations, sort_func)
end end
return bookmarks, highlights return annotations
end end
function ReaderAnnotation:onReadSettings(config) function ReaderAnnotation:onReadSettings(config)
local bookmarks, highlights
local annotations = config:readSetting("annotations") local annotations = config:readSetting("annotations")
if annotations then if annotations then
-- Annotation formats in crengine and mupdf are incompatible.
local has_annotations = #annotations > 0 local has_annotations = #annotations > 0
local annotations_type = has_annotations and type(annotations[1].page) local annotations_type = has_annotations and type(annotations[1].page)
-- Annotation formats in crengine and mupdf are incompatible.
if self.ui.rolling and annotations_type ~= "string" then -- incompatible format loaded, or empty if self.ui.rolling and annotations_type ~= "string" then -- incompatible format loaded, or empty
if has_annotations then -- backup incompatible format if not empty if has_annotations then -- backup incompatible format if not empty
config:saveSetting("annotations_paging", annotations) config:saveSetting("annotations_paging", annotations)
@ -132,66 +110,233 @@ function ReaderAnnotation:onReadSettings(config)
annotations = config:readSetting("annotations_paging") or {} annotations = config:readSetting("annotations_paging") or {}
config:delSetting("annotations_paging") config:delSetting("annotations_paging")
end end
bookmarks, highlights = self:getBookmarksHighlightsFromAnnotations(annotations)
self.annotations = annotations self.annotations = annotations
else -- old bookmarks/highlights else -- first run
bookmarks = config:readSetting("bookmarks") or {} self.ui:registerPostInitCallback(function()
highlights = config:readSetting("highlight") or {} self:createAnnotations(config)
local has_bookmarks = #bookmarks > 0 end)
local bookmarks_type = has_bookmarks and type(bookmarks[1].page) end
if self.ui.rolling then end
if bookmarks_type == "string" then -- compatible format loaded, check for incompatible old backup
if config:has("bookmarks_paging") then -- backup incompatible old backup function ReaderAnnotation:createAnnotations(config)
local bookmarks_paging = config:readSetting("bookmarks_paging") local bookmarks = config:readSetting("bookmarks") or {}
local highlights_paging = config:readSetting("highlight_paging") local highlights = config:readSetting("highlight") or {}
local annotations_paging = self:getAnnotationsFromBookmarksHighlights(bookmarks_paging, highlights_paging)
config:saveSetting("annotations_paging", annotations_paging) if config:hasNot("highlights_imported") then
config:delSetting("bookmarks_paging") -- old bookmarks were not created along the highlights
config:delSetting("highlight_paging") for page, hls in pairs(highlights) do
end for _, hl in ipairs(hls) do
else -- incompatible format loaded, or empty local hl_page = self.ui.paging and page or hl.pos0
if has_bookmarks then -- backup incompatible format if not empty -- highlights saved by some old versions don't have pos0 field
annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights) -- we just ignore those highlights
config:saveSetting("annotations_paging", annotations) if hl_page then
local item = {
datetime = hl.datetime,
highlighted = true,
notes = hl.text,
page = hl_page,
pos0 = hl.pos0,
pos1 = hl.pos1,
}
if self.ui.paging then
item.pos0.page = page
item.pos1.page = page
end
table.insert(bookmarks, item)
end end
-- load compatible format end
bookmarks = config:readSetting("bookmarks_rolling") or {} end
highlights = config:readSetting("highlight_rolling") or {} end
-- Bookmarks/highlights formats in crengine and mupdf are incompatible.
local has_bookmarks = #bookmarks > 0
local bookmarks_type = has_bookmarks and type(bookmarks[1].page)
if self.ui.rolling then
if bookmarks_type == "string" then -- compatible format loaded, check for incompatible old backup
if config:has("bookmarks_paging") then -- save incompatible old backup
local bookmarks_paging = config:readSetting("bookmarks_paging")
local highlights_paging = config:readSetting("highlight_paging")
local annotations_paging = self:getAnnotationsFromBookmarksHighlights(bookmarks_paging, highlights_paging)
config:saveSetting("annotations_paging", annotations_paging)
config:delSetting("bookmarks_paging")
config:delSetting("highlight_paging")
end
else -- incompatible format loaded, or empty
if has_bookmarks then -- save incompatible format if not empty
annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights)
config:saveSetting("annotations_paging", annotations)
end
-- load compatible format
bookmarks = config:readSetting("bookmarks_rolling") or {}
highlights = config:readSetting("highlight_rolling") or {}
config:delSetting("bookmarks_rolling")
config:delSetting("highlight_rolling")
end
else -- self.ui.paging
if bookmarks_type == "number" then
if config:has("bookmarks_rolling") then
local bookmarks_rolling = config:readSetting("bookmarks_rolling")
local highlights_rolling = config:readSetting("highlight_rolling")
local annotations_rolling = self:getAnnotationsFromBookmarksHighlights(bookmarks_rolling, highlights_rolling)
config:saveSetting("annotations_rolling", annotations_rolling)
config:delSetting("bookmarks_rolling") config:delSetting("bookmarks_rolling")
config:delSetting("highlight_rolling") config:delSetting("highlight_rolling")
end end
else else
if bookmarks_type == "number" then if has_bookmarks then
if config:has("bookmarks_rolling") then annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights)
local bookmarks_rolling = config:readSetting("bookmarks_rolling") config:saveSetting("annotations_rolling", annotations)
local highlights_rolling = config:readSetting("highlight_rolling") end
local annotations_rolling = self:getAnnotationsFromBookmarksHighlights(bookmarks_rolling, highlights_rolling) bookmarks = config:readSetting("bookmarks_paging") or {}
config:saveSetting("annotations_rolling", annotations_rolling) highlights = config:readSetting("highlight_paging") or {}
config:delSetting("bookmarks_rolling") config:delSetting("bookmarks_paging")
config:delSetting("highlight_rolling") config:delSetting("highlight_paging")
end
end
self.annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights, true)
end
function ReaderAnnotation:onCloseDocument()
self:updatePageNumbers()
self.ui.doc_settings:saveSetting("annotations", self.annotations)
end
-- items handling
function ReaderAnnotation:isItemInPositionOrderRolling(a, b)
local a_page = self.document:getPageFromXPointer(a.page)
local b_page = self.document:getPageFromXPointer(b.page)
if a_page == b_page then -- both items in the same page
if a.drawer and b.drawer then -- both items are highlights, compare positions
local compare_xp = self.document:compareXPointers(a.page, b.page)
if compare_xp then
if compare_xp == 0 then -- both highlights with the same start, compare ends
compare_xp = self.document:compareXPointers(a.pos1, b.pos1)
if compare_xp then
return compare_xp > 0
end
logger.warn("Invalid xpointer in highlight:", a.pos1, b.pos1)
return true
end end
return compare_xp > 0
end
-- if compare_xp is nil, some xpointer is invalid and "a" will be sorted first to page 1
logger.warn("Invalid xpointer in highlight:", a.page, b.page)
return true
end
return not a.drawer -- have page bookmarks before highlights
end
return a_page < b_page
end
function ReaderAnnotation:isItemInPositionOrderPaging(a, b)
if a.page == b.page then -- both items in the same page
if a.drawer and b.drawer then -- both items are highlights, compare positions
local is_reflow = self.document.configurable.text_wrap -- save reflow mode
self.document.configurable.text_wrap = 0 -- native positions
-- sort start and end positions of each highlight
local a_start, a_end, b_start, b_end, result
if self.document:comparePositions(a.pos0, a.pos1) > 0 then
a_start, a_end = a.pos0, a.pos1
else
a_start, a_end = a.pos1, a.pos0
end
if self.document:comparePositions(b.pos0, b.pos1) > 0 then
b_start, b_end = b.pos0, b.pos1
else else
if has_bookmarks then b_start, b_end = b.pos1, b.pos0
annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights) end
config:saveSetting("annotations_rolling", annotations) -- compare start positions
local compare_pos = self.document:comparePositions(a_start, b_start)
if compare_pos == 0 then -- both highlights with the same start, compare ends
result = self.document:comparePositions(a_end, b_end) > 0
else
result = compare_pos > 0
end
self.document.configurable.text_wrap = is_reflow -- restore reflow mode
return result
end
return not a.drawer -- have page bookmarks before highlights
end
return a.page < b.page
end
function ReaderAnnotation:getItemIndex(item, no_binary)
local doesMatch
if item.datetime then
doesMatch = function(a, b)
return a.datetime == b.datetime
end
else
if self.ui.rolling then
doesMatch = function(a, b)
if a.text ~= b.text or a.pos0 ~= b.pos0 or a.pos1 ~= b.pos1 then
return false
end end
bookmarks = config:readSetting("bookmarks_paging") or {} return true
highlights = config:readSetting("highlight_paging") or {} end
config:delSetting("bookmarks_paging") else
config:delSetting("highlight_paging") doesMatch = function(a, b)
if a.text ~= b.text or a.pos0.page ~= b.pos0.page
or a.pos0.x ~= b.pos0.x or a.pos1.x ~= b.pos1.x
or a.pos0.y ~= b.pos0.y or a.pos1.y ~= b.pos1.y then
return false
end
return true
end
end
end
if not no_binary then
local isInOrder = self.ui.rolling and self.isItemInPositionOrderRolling or self.isItemInPositionOrderPaging
local _start, _end, _middle = 1, #self.annotations
while _start <= _end do
_middle = bit.rshift(_start + _end, 1)
local v = self.annotations[_middle]
if doesMatch(item, v) then
return _middle
elseif isInOrder(self, item, v) then
_end = _middle - 1
else
_start = _middle + 1
end end
end end
self.annotations = self:getAnnotationsFromBookmarksHighlights(bookmarks, highlights)
end end
self.ui.bookmark.bookmarks = bookmarks
self.view.highlight.saved = highlights for i, v in ipairs(self.annotations) do
if doesMatch(item, v) then
return i
end
end
end end
function ReaderAnnotation:onCloseDocument() function ReaderAnnotation:getInsertionIndex(item)
local annotations = self:getAnnotationsFromBookmarksHighlights(self.ui.bookmark.bookmarks, self.view.highlight.saved, true) local isInOrder = self.ui.rolling and self.isItemInPositionOrderRolling or self.isItemInPositionOrderPaging
self.ui.doc_settings:saveSetting("annotations", annotations) local _start, _end, _middle, direction = 1, #self.annotations, 1, 0
self.ui.doc_settings:saveSetting("bookmarks", self.ui.bookmark.bookmarks) while _start <= _end do
self.ui.doc_settings:saveSetting("highlight", self.view.highlight.saved) _middle = bit.rshift(_start + _end, 1)
if isInOrder(self, item, self.annotations[_middle]) then
_end, direction = _middle - 1, 0
else
_start, direction = _middle + 1, 1
end
end
return _middle + direction
end
function ReaderAnnotation:addItem(item)
local index = self:getInsertionIndex(item)
table.insert(self.annotations, index, item)
return index
end
function ReaderAnnotation:updatePageNumbers()
if self.ui.rolling then
for _, item in ipairs(self.annotations) do
item.pageno = self.ui.bookmark:getBookmarkPageString(item.page)
end
end
end end
return ReaderAnnotation return ReaderAnnotation

Loading…
Cancel
Save