Bookmark search (#8504)

From bookmark list, main menu and with a gesture.
reviewable/pr8513/r1
hius07 2 years ago committed by GitHub
parent 91c4aeb2e5
commit 785eb5f3ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,7 +9,9 @@ local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local LineWidget = require("ui/widget/linewidget")
local Menu = require("ui/widget/menu")
local Size = require("ui/size")
local TextViewer = require("ui/widget/textviewer")
local UIManager = require("ui/uimanager")
local Utf8Proc = require("ffi/utf8proc")
@ -174,6 +176,15 @@ function ReaderBookmark:addToMainMenu(menu_items)
},
},
}
menu_items.bookmark_search = {
text = _("Bookmark search"),
enabled_func = function()
return self:hasBookmarks()
end,
callback = function()
self:onSearchBookmark()
end,
}
end
function ReaderBookmark:enableBookmarkBrowsingMode()
@ -385,37 +396,33 @@ function ReaderBookmark:updateHighlightsIfNeeded()
self.ui.doc_settings:saveSetting("bookmarks_version", 20200615)
end
function ReaderBookmark:onShowBookmark()
function ReaderBookmark:onShowBookmark(match_table)
self.select_mode = false
self.filtered_mode = false
self.filtered_mode = match_table and true or false
self:updateHighlightsIfNeeded()
-- build up item_table
local item_table = {}
local is_reverse_sorting = G_reader_settings:nilOrTrue("bookmarks_items_reverse_sorting")
local curr_page = self.ui.rolling and self.ui.document:getXPointer() or self.ui.paging.current_page
curr_page = self:getBookmarkPageString(curr_page)
local num = #self.bookmarks + 1
for i, v in ipairs(self.bookmarks) do
local is_auto_text
for i = 1, #self.bookmarks do
-- bookmarks are internally sorted by descending page numbers
local v = self.bookmarks[is_reverse_sorting and i or num - i]
if v.text == nil or v.text == "" then
is_auto_text = true
v.text = self:getBookmarkAutoText(v)
else
is_auto_text = self:isBookmarkAutoText(v)
end
-- bookmarks are internally sorted by descending page numbers
local k = is_reverse_sorting and i or num - i
item_table[k] = util.tableDeepCopy(v)
if v.highlighted then
if is_auto_text then
item_table[k].type = "highlight"
else
item_table[k].type = "note"
local item = util.tableDeepCopy(v)
item.type = self:getBookmarkType(item)
if not match_table or self:doesBookmarkMatchTable(item, match_table) then
item.text_orig = item.text or item.notes
item.text = DISPLAY_PREFIX[item.type] .. item.text_orig
item.mandatory = self:getBookmarkPageString(item.page)
if item.mandatory == curr_page then
item.bold = true
end
else
item_table[k].type = "bookmark"
table.insert(item_table, item)
end
item_table[k].text_orig = v.text or v.notes
item_table[k].text = DISPLAY_PREFIX[item_table[k].type] .. item_table[k].text_orig
item_table[k].mandatory = self:getBookmarkPageString(v.page)
end
local items_per_page = G_reader_settings:readSetting("bookmarks_items_per_page")
@ -424,7 +431,7 @@ function ReaderBookmark:onShowBookmark()
local show_separator = G_reader_settings:isTrue("bookmarks_items_show_separator")
local bm_menu = Menu:new{
title = _("Bookmarks"),
title = self.filtered_mode and _("Bookmarks (search results)") or _("Bookmarks"),
item_table = item_table,
is_borderless = true,
is_popout = false,
@ -491,7 +498,7 @@ function ReaderBookmark:onShowBookmark()
table.remove(item_table, i)
end
end
bm_menu:switchItemTable(self.filtered_mode and _("Bookmarks (filtered)") or _("Bookmarks"), item_table, -1)
bm_menu:switchItemTable(bookmark.filtered_mode and _("Bookmarks (search results)") or _("Bookmarks"), item_table, -1)
end,
other_buttons_first = true,
other_buttons = {
@ -526,7 +533,7 @@ function ReaderBookmark:onShowBookmark()
end
end
self.select_mode = false
bm_menu:switchItemTable(self.filtered_mode and _("Bookmarks (filtered)") or _("Bookmarks"), item_table)
bm_menu:switchItemTable(bookmark.filtered_mode and _("Bookmarks (search results)") or _("Bookmarks"), item_table)
end,
},
{
@ -604,91 +611,10 @@ function ReaderBookmark:onShowBookmark()
end,
},
{
text = _("Filter bookmarks"),
text = _("Search bookmarks"),
callback = function()
UIManager:close(self.textviewer)
local input_dialog, check_button_bookmark, check_button_highlight, check_button_note
input_dialog = InputDialog:new{
title = _("Filter bookmarks"),
input_hint = _("(containing text)"),
buttons = {
{
{
text = _("Close"),
callback = function()
UIManager:close(input_dialog)
end,
},
{
text = _("Apply"),
is_enter_default = true,
callback = function()
if check_button_bookmark.checked
or check_button_highlight.checked
or check_button_note.checked then
local search_str = input_dialog:getInputText()
local is_search_str = false
if search_str ~= "" then
is_search_str = true
search_str = Utf8Proc.lowercase(util.fixUtf8(search_str, "?"))
end
for i = #item_table, 1, -1 do
local bm_item = item_table[i]
if (check_button_bookmark.checked and bm_item.type == "bookmark")
or (check_button_highlight.checked and bm_item.type == "highlight")
or (check_button_note.checked and bm_item.type == "note") then
if is_search_str then
local bm_text = bm_item.notes .. bm_item.text
bm_text = Utf8Proc.lowercase(util.fixUtf8(bm_text, "?"))
if not bm_text:find(search_str) then
table.remove(item_table, i)
end
end
else
table.remove(item_table, i)
end
end
UIManager:close(input_dialog)
bm_menu:switchItemTable(_("Bookmarks (filtered)"), item_table)
self.filtered_mode = true
end
end,
},
},
},
}
check_button_highlight = CheckButton:new{
text = " " .. DISPLAY_PREFIX["highlight"] .. _("highlights"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_highlight:toggleCheck()
end,
}
input_dialog:addWidget(check_button_highlight)
check_button_note = CheckButton:new{
text = " " .. DISPLAY_PREFIX["note"] .. _("notes"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_note:toggleCheck()
end,
}
input_dialog:addWidget(check_button_note)
check_button_bookmark = CheckButton:new{
text = " " .. DISPLAY_PREFIX["bookmark"] .. _("page bookmarks"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_bookmark:toggleCheck()
end,
}
input_dialog:addWidget(check_button_bookmark)
UIManager:show(input_dialog)
input_dialog:onShowKeyboard()
bookmark:onSearchBookmark(bm_menu)
end,
},
},
@ -910,35 +836,28 @@ function ReaderBookmark:renameBookmark(item, from_highlight)
local value = self.input:getInputValue()
if value == "" then -- blank input resets the 'text' field to auto-text
value = self:getBookmarkAutoText(bookmark)
if bookmark.type == "note" then
bookmark.type = "highlight"
end
else
if bookmark.type == "highlight" then
bookmark.type = "note"
end
end
bookmark.text = value or bookmark.notes
for __, bm in ipairs(self.bookmarks) do
if bookmark.datetime == bm.datetime and bookmark.page == bm.page then
bm.text = value
bookmark.text_orig = value or bookmark.notes
bookmark.text = bookmark.text_orig
-- A bookmark isn't necessarily a highlight (it doesn't have pboxes)
if bookmark.pboxes then
local setting = G_reader_settings:readSetting("save_document")
if setting ~= "disable" then
self.ui.document:updateHighlightContents(bookmark.page, bookmark, value or bookmark.notes)
self.ui.document:updateHighlightContents(bookmark.page, bookmark, bookmark.text)
end
end
UIManager:close(self.input)
if not from_highlight then
bookmark.text = DISPLAY_PREFIX[bookmark.type] .. bookmark.text
self.refresh()
end
break
end
end
UIManager:close(self.input)
if not from_highlight then
bookmark.type = self:getBookmarkType(bookmark)
bookmark.text_orig = bookmark.text
bookmark.text = DISPLAY_PREFIX[bookmark.type] .. bookmark.text
self.refresh()
end
end,
},
}
@ -948,6 +867,127 @@ function ReaderBookmark:renameBookmark(item, from_highlight)
self.input:onShowKeyboard()
end
function ReaderBookmark:onSearchBookmark(bm_menu)
local input_dialog
local check_button_case, separator, check_button_bookmark, check_button_highlight, check_button_note
input_dialog = InputDialog:new{
title = _("Search bookmarks"),
buttons = {
{
{
text = _("Cancel"),
callback = function()
UIManager:close(input_dialog)
end,
},
{
text = _("Search"),
is_enter_default = true,
callback = function()
local search_str = input_dialog:getInputText()
if not check_button_case.checked then
search_str = Utf8Proc.lowercase(util.fixUtf8(search_str, "?"))
end
local match_table = {
search_str = search_str,
bookmark = check_button_bookmark.checked,
highlight = check_button_highlight.checked,
note = check_button_note.checked,
case_sensitive = check_button_case.checked,
}
UIManager:close(input_dialog)
if bm_menu then -- from bookmark list
for i = #bm_menu.item_table, 1, -1 do
if not self:doesBookmarkMatchTable(bm_menu.item_table[i], match_table) then
table.remove(bm_menu.item_table, i)
end
end
bm_menu:switchItemTable(_("Bookmarks (search results)"), bm_menu.item_table)
self.filtered_mode = true
else -- from main menu
self:onShowBookmark(match_table)
end
end,
},
},
},
}
check_button_case = CheckButton:new{
text = " " .. _("Case sensitive"),
checked = false,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_case:toggleCheck()
end,
}
input_dialog:addWidget(check_button_case)
separator = CenterContainer:new{
dimen = Geom:new{
w = input_dialog._input_widget.width,
h = 2 * Size.span.vertical_large,
},
LineWidget:new{
background = Blitbuffer.COLOR_DARK_GRAY,
dimen = Geom:new{
w = input_dialog._input_widget.width,
h = Size.line.medium,
}
},
}
input_dialog:addWidget(separator)
check_button_highlight = CheckButton:new{
text = " " .. DISPLAY_PREFIX["highlight"] .. _("highlights"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_highlight:toggleCheck()
end,
}
input_dialog:addWidget(check_button_highlight)
check_button_note = CheckButton:new{
text = " " .. DISPLAY_PREFIX["note"] .. _("notes"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_note:toggleCheck()
end,
}
input_dialog:addWidget(check_button_note)
check_button_bookmark = CheckButton:new{
text = " " .. DISPLAY_PREFIX["bookmark"] .. _("page bookmarks"),
checked = true,
parent = input_dialog,
max_width = input_dialog._input_widget.width,
callback = function()
check_button_bookmark:toggleCheck()
end,
}
input_dialog:addWidget(check_button_bookmark)
UIManager:show(input_dialog)
input_dialog:onShowKeyboard()
end
function ReaderBookmark:doesBookmarkMatchTable(item, match_table)
if match_table[item.type] then
if match_table.search_str == "" then
return true
else
local text = item.notes
if item.text then -- search in the highlighted text and in the note
text = text .. "\u{FFFF}" .. item.text
end
if not match_table.case_sensitive then
text = Utf8Proc.lowercase(util.fixUtf8(text, "?"))
end
return text:find(match_table.search_str)
end
end
end
function ReaderBookmark:toggleBookmark(pn_or_xp)
local index = self:getDogearBookmarkIndex(pn_or_xp)
if index then
@ -1087,8 +1127,20 @@ function ReaderBookmark:getNumberOfHighlightsAndNotes()
return highlights, notes
end
function ReaderBookmark:getBookmarkType(bookmark)
if bookmark.highlighted then
if self:isBookmarkAutoText(bookmark) then
return "highlight"
else
return "note"
end
else
return "bookmark"
end
end
function ReaderBookmark:getBookmarkPageString(page)
if not self.ui.document.info.has_pages then
if self.ui.rolling then
if self.ui.pagemap and self.ui.pagemap:wantsPageLabels() then
page = self.ui.pagemap:getXPointerPageLabel(page, true)
else
@ -1117,7 +1169,8 @@ end
--- Check if the 'text' field has not been edited manually
function ReaderBookmark:isBookmarkAutoText(bookmark)
return (bookmark.text == nil) or (bookmark.text == self:getBookmarkAutoText(bookmark, true))
return (bookmark.text == nil) or (bookmark.text == bookmark.notes)
or (bookmark.text == self:getBookmarkAutoText(bookmark, true))
end
function ReaderBookmark:isHighlightAutoText(item)

@ -118,6 +118,7 @@ local settingsList = {
clear_location_history = {category="none", event="ClearLocationStack", arg=true, title=_("Clear location history"), reader=true, separator=true},
toc = {category="none", event="ShowToc", title=_("Table of contents"), reader=true},
bookmarks = {category="none", event="ShowBookmark", title=_("Bookmarks"), reader=true},
bookmark_search = {category="none", event="SearchBookmark", title=_("Bookmark search"), reader=true},
book_status = {category="none", event="ShowBookStatus", title=_("Book status"), reader=true},
book_info = {category="none", event="ShowBookInfo", title=_("Book information"), reader=true},
book_description = {category="none", event="ShowBookDescription", title=_("Book description"), reader=true},
@ -278,6 +279,7 @@ local dispatcher_menu_order = {
"toc",
"bookmarks",
"bookmark_search",
"book_status",
"book_info",

@ -187,6 +187,7 @@ local order = {
"----------------------------",
"find_book_in_calibre_catalog",
"fulltext_search",
"bookmark_search",
},
filemanager = {},
main = {

Loading…
Cancel
Save