2
0
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:
Frans de Jonge 2018-03-31 21:19:31 +02:00 committed by GitHub
parent c332d517f7
commit 2c1178896c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 128 additions and 36 deletions

View 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

View File

@ -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,

View File

@ -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

View File

@ -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()