mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
[feat] Add ReaderBack (#3821)
This implements a reasonable facsimile of going back on Android. The back button first goes back in a history of visited pages. When there's no history left, it closes the app. Fixes #3816.
This commit is contained in:
parent
c332d517f7
commit
2c1178896c
81
frontend/apps/reader/modules/readerback.lua
Normal file
81
frontend/apps/reader/modules/readerback.lua
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
local Device = require("device")
|
||||||
|
local Event = require("ui/event")
|
||||||
|
local EventListener = require("ui/widget/eventlistener")
|
||||||
|
local logger = require("logger")
|
||||||
|
local util = require("util")
|
||||||
|
|
||||||
|
local ReaderBack = EventListener:new{
|
||||||
|
location_stack = {},
|
||||||
|
-- a limit not intended to be a practical limit but just a failsafe
|
||||||
|
max_stack = 5000,
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReaderBack:init()
|
||||||
|
if Device:hasKeys() then
|
||||||
|
self.ui.key_events.Back = { {"Back"}, doc = "Reader back" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderBack:_getCurrentLocation()
|
||||||
|
local current_location
|
||||||
|
|
||||||
|
if self.ui.document.info.has_pages then
|
||||||
|
current_location = self.ui.paging:getBookLocation()
|
||||||
|
else
|
||||||
|
current_location = {
|
||||||
|
xpointer = self.ui.rolling:getBookLocation(),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return current_location
|
||||||
|
end
|
||||||
|
|
||||||
|
local ignore_location
|
||||||
|
|
||||||
|
function ReaderBack:addCurrentLocationToStack()
|
||||||
|
local location_stack = self.location_stack
|
||||||
|
local new_location = self:_getCurrentLocation()
|
||||||
|
|
||||||
|
if util.tableEquals(ignore_location, new_location) then return end
|
||||||
|
|
||||||
|
table.insert(location_stack, new_location)
|
||||||
|
|
||||||
|
if #location_stack > self.max_stack then
|
||||||
|
table.remove(location_stack, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scroll mode crengine
|
||||||
|
function ReaderBack:onPosUpdate()
|
||||||
|
self:addCurrentLocationToStack()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Paged media
|
||||||
|
function ReaderBack:onPageUpdate()
|
||||||
|
self:addCurrentLocationToStack()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when loading new document
|
||||||
|
function ReaderBack:onReadSettings(config)
|
||||||
|
self.location_stack = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderBack:onBack()
|
||||||
|
local location_stack = self.location_stack
|
||||||
|
|
||||||
|
if #location_stack > 1 then
|
||||||
|
local saved_location = table.remove(location_stack)
|
||||||
|
|
||||||
|
if saved_location then
|
||||||
|
ignore_location = self:_getCurrentLocation()
|
||||||
|
logger.dbg("[ReaderBack] restoring:", saved_location)
|
||||||
|
self.ui:handleEvent(Event:new('RestoreBookLocation', saved_location))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
logger.dbg("[ReaderBack] no location history, closing")
|
||||||
|
self.ui:handleEvent(Event:new("Close"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ReaderBack
|
@ -17,6 +17,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
|||||||
local InputDialog = require("ui/widget/inputdialog")
|
local InputDialog = require("ui/widget/inputdialog")
|
||||||
local PluginLoader = require("pluginloader")
|
local PluginLoader = require("pluginloader")
|
||||||
local ReaderActivityIndicator = require("apps/reader/modules/readeractivityindicator")
|
local ReaderActivityIndicator = require("apps/reader/modules/readeractivityindicator")
|
||||||
|
local ReaderBack = require("apps/reader/modules/readerback")
|
||||||
local ReaderBookmark = require("apps/reader/modules/readerbookmark")
|
local ReaderBookmark = require("apps/reader/modules/readerbookmark")
|
||||||
local ReaderConfig = require("apps/reader/modules/readerconfig")
|
local ReaderConfig = require("apps/reader/modules/readerconfig")
|
||||||
local ReaderCoptListener = require("apps/reader/modules/readercoptlistener")
|
local ReaderCoptListener = require("apps/reader/modules/readercoptlistener")
|
||||||
@ -97,11 +98,6 @@ function ReaderUI:init()
|
|||||||
|
|
||||||
if Device:hasKeys() then
|
if Device:hasKeys() then
|
||||||
self.key_events.Home = { {"Home"}, doc = "open file browser" }
|
self.key_events.Home = { {"Home"}, doc = "open file browser" }
|
||||||
if Device:isSDL() then
|
|
||||||
--if in the desktop emulator
|
|
||||||
--add the old Back key to exit koreader
|
|
||||||
self.key_events.Close = { {"Back"}, doc = "Exit koreader" }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- a view container (so it must be child #1!)
|
-- a view container (so it must be child #1!)
|
||||||
@ -299,6 +295,11 @@ function ReaderUI:init()
|
|||||||
})
|
})
|
||||||
self.disable_double_tap = G_reader_settings:readSetting("disable_double_tap") ~= false
|
self.disable_double_tap = G_reader_settings:readSetting("disable_double_tap") ~= false
|
||||||
end
|
end
|
||||||
|
-- back location stack
|
||||||
|
self:registerModule("back", ReaderBack:new{
|
||||||
|
ui = self,
|
||||||
|
view = self.view,
|
||||||
|
})
|
||||||
-- fulltext search
|
-- fulltext search
|
||||||
self:registerModule("search", ReaderSearch:new{
|
self:registerModule("search", ReaderSearch:new{
|
||||||
dialog = self.dialog,
|
dialog = self.dialog,
|
||||||
|
@ -95,6 +95,46 @@ function util.secondsToClock(seconds, withoutSeconds)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[--
|
||||||
|
Compares values in two different tables.
|
||||||
|
|
||||||
|
Source: <a href="https://stackoverflow.com/a/32660766/2470572">https://stackoverflow.com/a/32660766/2470572</a>
|
||||||
|
]]
|
||||||
|
---- @param o1 Lua table
|
||||||
|
---- @param o2 Lua table
|
||||||
|
---- @bool ignore_mt
|
||||||
|
---- @treturn boolean
|
||||||
|
function util.tableEquals(o1, o2, ignore_mt)
|
||||||
|
if o1 == o2 then return true end
|
||||||
|
local o1Type = type(o1)
|
||||||
|
local o2Type = type(o2)
|
||||||
|
if o1Type ~= o2Type then return false end
|
||||||
|
if o1Type ~= 'table' then return false end
|
||||||
|
|
||||||
|
if not ignore_mt then
|
||||||
|
local mt1 = getmetatable(o1)
|
||||||
|
if mt1 and mt1.__eq then
|
||||||
|
--compare using built in method
|
||||||
|
return o1 == o2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local keySet = {}
|
||||||
|
|
||||||
|
for key1, value1 in pairs(o1) do
|
||||||
|
local value2 = o2[key1]
|
||||||
|
if value2 == nil or util.tableEquals(value1, value2, ignore_mt) == false then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
keySet[key1] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for key2, _ in pairs(o2) do
|
||||||
|
if not keySet[key2] then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns number of keys in a table.
|
--- Returns number of keys in a table.
|
||||||
---- @param T Lua table
|
---- @param T Lua table
|
||||||
---- @treturn int number of keys in table T
|
---- @treturn int number of keys in table T
|
||||||
|
@ -5,37 +5,7 @@ describe("InputText widget module", function()
|
|||||||
require("commonrequire")
|
require("commonrequire")
|
||||||
InputText = require("ui/widget/inputtext")
|
InputText = require("ui/widget/inputtext")
|
||||||
|
|
||||||
-- thanks to https://stackoverflow.com/a/32660766/2470572
|
equals = require("util").tableEquals
|
||||||
equals = function(o1, o2, ignore_mt)
|
|
||||||
if o1 == o2 then return true end
|
|
||||||
local o1Type = type(o1)
|
|
||||||
local o2Type = type(o2)
|
|
||||||
if o1Type ~= o2Type then return false end
|
|
||||||
if o1Type ~= 'table' then return false end
|
|
||||||
|
|
||||||
if not ignore_mt then
|
|
||||||
local mt1 = getmetatable(o1)
|
|
||||||
if mt1 and mt1.__eq then
|
|
||||||
--compare using built in method
|
|
||||||
return o1 == o2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local keySet = {}
|
|
||||||
|
|
||||||
for key1, value1 in pairs(o1) do
|
|
||||||
local value2 = o2[key1]
|
|
||||||
if value2 == nil or equals(value1, value2, ignore_mt) == false then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
keySet[key1] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for key2, _ in pairs(o2) do
|
|
||||||
if not keySet[key2] then return false end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("addChars()", function()
|
describe("addChars()", function()
|
||||||
|
Loading…
Reference in New Issue
Block a user