diff --git a/frontend/apps/reader/modules/readerbookmark.lua b/frontend/apps/reader/modules/readerbookmark.lua index 0a12ab177..187ecea3c 100644 --- a/frontend/apps/reader/modules/readerbookmark.lua +++ b/frontend/apps/reader/modules/readerbookmark.lua @@ -395,4 +395,16 @@ function ReaderBookmark:onGotoNextBookmark(pn_or_xp) return true end +function ReaderBookmark:getLatestBookmark() + local latest_bookmark = nil + local latest_bookmark_datetime = "0" + for i = 1, #self.bookmarks do + if self.bookmarks[i].datetime > latest_bookmark_datetime then + latest_bookmark_datetime = self.bookmarks[i].datetime + latest_bookmark = self.bookmarks[i] + end + end + return latest_bookmark +end + return ReaderBookmark diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index 56e3d6a40..879c3fc91 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -71,6 +71,14 @@ local function isSwipeToFollowFirstLinkEnabled() return G_reader_settings:readSetting("swipe_to_follow_first_link") == true end +local function isSwipeToFollowNearestLinkEnabled() + return G_reader_settings:readSetting("swipe_to_follow_nearest_link") == true +end + +local function isSwipeToJumpToLatestBookmarkEnabled() + return G_reader_settings:readSetting("swipe_to_jump_to_latest_bookmark") == true +end + function ReaderLink:addToMainMenu(menu_items) -- insert table to main reader menu menu_items.follow_links = { @@ -101,11 +109,34 @@ function ReaderLink:addToMainMenu(menu_items) end, }, { - text = _("Swipe to follow first link"), + text = _("Swipe to follow first link on page"), checked_func = isSwipeToFollowFirstLinkEnabled, callback = function() G_reader_settings:saveSetting("swipe_to_follow_first_link", not isSwipeToFollowFirstLinkEnabled()) + if isSwipeToFollowFirstLinkEnabled() then + G_reader_settings:delSetting("swipe_to_follow_nearest_link") -- can't have both + end + end, + }, + { + text = _("Swipe to follow nearest link"), + checked_func = isSwipeToFollowNearestLinkEnabled, + callback = function() + G_reader_settings:saveSetting("swipe_to_follow_nearest_link", + not isSwipeToFollowNearestLinkEnabled()) + if isSwipeToFollowNearestLinkEnabled() then + G_reader_settings:delSetting("swipe_to_follow_first_link") -- can't have both + end + end, + separator = true, + }, + { + text = _("Swipe to jump to latest bookmark"), + checked_func = isSwipeToJumpToLatestBookmarkEnabled, + callback = function() + G_reader_settings:saveSetting("swipe_to_jump_to_latest_bookmark", + not isSwipeToJumpToLatestBookmarkEnabled()) end, }, } @@ -239,15 +270,24 @@ function ReaderLink:onSwipe(_, ges) return self:onGoBackLink() end elseif ges.direction == "west" then + local ret = false if isSwipeToFollowFirstLinkEnabled() then - return self:onGoToFirstLink(ges) + ret = self:onGoToPageLink(ges, true) + elseif isSwipeToFollowNearestLinkEnabled() then + ret = self:onGoToPageLink(ges) + end + -- If no link found, or no follow link option enabled, + -- jump to latest bookmark (if enabled) + if not ret and isSwipeToJumpToLatestBookmarkEnabled() then + ret = self:onGoToLatestBookmark(ges) end + return ret end end ---- Goes to first link on page. -function ReaderLink:onGoToFirstLink(ges) - local firstlink = nil +--- Goes to link nearest to the gesture (or first link in page) +function ReaderLink:onGoToPageLink(ges, use_page_first_link) + local selected_link = nil if self.ui.document.info.has_pages then local pos = self.view:screenToPageTransform(ges.pos) if not pos then @@ -268,16 +308,28 @@ function ReaderLink:onGoToFirstLink(ges) -- ["x0"] = 97, -- ["page"] = 347 -- }, - -- Links may not be in the order they are in the page, so let's - -- find the one with the smallest y0. + local pos_x, pos_y = ges.pos.x, ges.pos.y + local shortest_dist = nil local first_y0 = nil for _, link in ipairs(links) do if link["page"] then - if first_y0 == nil or link["y0"] < first_y0 then - -- onGotoLink()'s GotoPage event needs the link - -- itself, and will use its "page" value - firstlink = link - first_y0 = link["y0"] + if use_page_first_link then + -- Links may not be in the order they are in the page, so let's + -- find the one with the smallest y0. + if first_y0 == nil or link["y0"] < first_y0 then + selected_link = link + first_y0 = link["y0"] + end + else + local start_dist = math.pow(link.x0 - pos_x, 2) + math.pow(link.y0 - pos_y, 2) + local end_dist = math.pow(link.x1 - pos_x, 2) + math.pow(link.y1 - pos_y, 2) + local min_dist = math.min(start_dist, end_dist) + if shortest_dist == nil or min_dist < shortest_dist then + -- onGotoLink()'s GotoPage event needs the link + -- itself, and will use its "page" value + selected_link = link + shortest_dist = min_dist + end end end end @@ -304,16 +356,28 @@ function ReaderLink:onGoToFirstLink(ges) -- ["start_x"] = 352, -- ["start_y"] = 1201 -- }, - -- links may not be in the order they are in the page, so let's - -- find the one with the smallest start_y. + local pos_x, pos_y = ges.pos.x, ges.pos.y + local shortest_dist = nil local first_start_y = nil for _, link in ipairs(links) do if link["section"] then - if first_start_y == nil or link["start_y"] < first_start_y then - -- onGotoLink()'s GotoXPointer event needs - -- the "section" value - firstlink = link["section"] - first_start_y = link["start_y"] + if use_page_first_link then + -- links may not be in the order they are in the page, so let's + -- find the one with the smallest start_y. + if first_start_y == nil or link["start_y"] < first_start_y then + selected_link = link["section"] + first_start_y = link["start_y"] + end + else + local start_dist = math.pow(link.start_x - pos_x, 2) + math.pow(link.start_y - pos_y, 2) + local end_dist = math.pow(link.end_x - pos_x, 2) + math.pow(link.end_y - pos_y, 2) + local min_dist = math.min(start_dist, end_dist) + if shortest_dist == nil or min_dist < shortest_dist then + -- onGotoLink()'s GotoXPointer event needs + -- the "section" value + selected_link = link["section"] + shortest_dist = min_dist + end end end end @@ -323,8 +387,27 @@ function ReaderLink:onGoToFirstLink(ges) -- So let's clear them now. self.ui.document:clearSelection() end - if firstlink then - return self:onGotoLink(firstlink) + if selected_link then + return self:onGotoLink(selected_link) + end +end + +function ReaderLink:onGoToLatestBookmark(ges) + local latest_bookmark = self.ui.bookmark:getLatestBookmark() + if latest_bookmark then + if self.ui.document.info.has_pages then + -- self:onGotoLink() needs something with a page attribute. + -- we need to substract 1 to bookmark page, as links start from 0 + -- and onGotoLink will add 1 - we need a fake_link (with a single + -- page attribute) so we don't touch the bookmark itself + local fake_link = {} + fake_link.page = latest_bookmark.page - 1 + return self:onGotoLink(fake_link) + else + -- self:onGotoLink() needs a xpointer, that we find + -- as the bookmark page attribute + return self:onGotoLink(latest_bookmark.page) + end end end