2
0
mirror of https://github.com/koreader/koreader synced 2024-11-10 01:10:34 +00:00

Merge pull request #980 from chrox/collapsible_toc

refactoring readerrolling
This commit is contained in:
Qingping Hou 2014-10-11 01:01:56 -07:00
commit c69f77d5ab
9 changed files with 202 additions and 46 deletions

2
base

@ -1 +1 @@
Subproject commit e8385ad081470ba8aab214a187887b7870c1ada2 Subproject commit ce27f6ed762ec1046c94a540cc0d555eaeda9efd

View File

@ -175,15 +175,19 @@ end
function FileManager:showFiles(path) function FileManager:showFiles(path)
DEBUG("show home page") DEBUG("show home page")
local screen_mode = G_reader_settings:readSetting("fm_screen_mode") or "portrait"
Screen:setScreenMode(screen_mode)
path = path or G_reader_settings:readSetting("lastdir") or self:getDefaultDir() path = path or G_reader_settings:readSetting("lastdir") or self:getDefaultDir()
G_reader_settings:saveSetting("lastdir", path) G_reader_settings:saveSetting("lastdir", path)
UIManager:show(FileManager:new{ UIManager:show(FileManager:new{
dimen = Screen:getSize(), dimen = Screen:getSize(),
root_path = path, root_path = path,
onExit = function() onExit = function()
self.is_running = false
UIManager:quit() UIManager:quit()
end end
}) })
self.is_running = true
end end
function FileManager:copyFile(file) function FileManager:copyFile(file)

View File

@ -78,7 +78,7 @@ function ReaderConfig:onCloseCallback()
end end
-- event handler for readercropping -- event handler for readercropping
function ReaderConfig:onCloseConfig() function ReaderConfig:onCloseConfigMenu()
self.config_dialog:closeDialog() self.config_dialog:closeDialog()
end end

View File

@ -67,7 +67,7 @@ local ReaderCropping = InputContainer:new{}
function ReaderCropping:onPageCrop(mode) function ReaderCropping:onPageCrop(mode)
if mode == "auto" then return end if mode == "auto" then return end
self.ui:handleEvent(Event:new("CloseConfig")) self.ui:handleEvent(Event:new("CloseConfigMenu"))
-- backup original view dimen -- backup original view dimen
self.orig_view_dimen = Geom:new{w = self.view.dimen.w, h = self.view.dimen.h} self.orig_view_dimen = Geom:new{w = self.view.dimen.w, h = self.view.dimen.h}
-- backup original view bgcolor -- backup original view bgcolor

View File

@ -41,19 +41,18 @@ function ReaderMenu:init()
filemanager = { filemanager = {
icon = "resources/icons/appbar.cabinet.files.png", icon = "resources/icons/appbar.cabinet.files.png",
callback = function() callback = function()
self.ui:handleEvent(Event:new("RestoreScreenMode",
G_reader_settings:readSetting("screen_mode") or "portrait"))
self.ui:onClose() self.ui:onClose()
UIManager:quit() self:onTapCloseMenu()
local FileManager = require("apps/filemanager/filemanager") local FileManager = require("apps/filemanager/filemanager")
FileManager:showFiles() if not FileManager.is_running then
UIManager:quit()
FileManager:showFiles()
end
end, end,
}, },
home = { home = {
icon = "resources/icons/appbar.home.png", icon = "resources/icons/appbar.home.png",
callback = function() callback = function()
self.ui:handleEvent(Event:new("RestoreScreenMode",
G_reader_settings:readSetting("screen_mode") or "portrait"))
self.ui:onClose() self.ui:onClose()
UIManager:quit() UIManager:quit()
end, end,
@ -217,6 +216,11 @@ function ReaderMenu:onTapShowMenu()
return true return true
end end
function ReaderMenu:onTapCloseMenu()
self.ui:handleEvent(Event:new("CloseReaderMenu"))
self.ui:handleEvent(Event:new("CloseConfigMenu"))
end
function ReaderMenu:onSetDimensions(dimen) function ReaderMenu:onSetDimensions(dimen)
-- update listening according to new screen dimen -- update listening according to new screen dimen
if Device:isTouchDevice() then if Device:isTouchDevice() then

View File

@ -1,4 +1,5 @@
local InputContainer = require("ui/widget/container/inputcontainer") local InputContainer = require("ui/widget/container/inputcontainer")
local ReaderPanning = require("apps/reader/modules/readerpanning")
local Screen = require("ui/screen") local Screen = require("ui/screen")
local Device = require("ui/device") local Device = require("ui/device")
local Geom = require("ui/geometry") local Geom = require("ui/geometry")
@ -8,8 +9,27 @@ local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local DEBUG = require("dbg") local DEBUG = require("dbg")
local _ = require("gettext") local _ = require("gettext")
local ReaderPanning = require("apps/reader/modules/readerpanning")
--[[
Rolling is just like paging in page-based documents except that
sometimes (in scroll mode) there is no concept of page number to indicate
current progress.
There are three kind of progress measurements for credocuments.
1. page number (in page mode)
2. progress percentage (in scroll mode)
3. xpointer (in document dom structure)
We found that the first two measurements are not suitable for keeping a
record of the real progress. For example, when switching screen orientation
from portrait to landscape, or switching view mode from page to scroll, the
internal xpointer should not be used as the view dimen/mode is changed and
crengine's pagination mechanism will find a closest xpointer for the new view.
So if we change the screen orientation or view mode back, we cannot find the
original place since the internal xpointer is changed, which is counter-
intuitive as users didn't goto any other page.
The solution is that we keep a record of the internal xpointer and only change
it in explicit page turning. And use that xpointer for non-page-turning
rendering.
--]]
local ReaderRolling = InputContainer:new{ local ReaderRolling = InputContainer:new{
old_doc_height = nil, old_doc_height = nil,
old_page = nil, old_page = nil,
@ -17,6 +37,7 @@ local ReaderRolling = InputContainer:new{
-- only used for page view mode -- only used for page view mode
current_page= nil, current_page= nil,
doc_height = nil, doc_height = nil,
xpointer = nil,
panning_steps = ReaderPanning.panning_steps, panning_steps = ReaderPanning.panning_steps,
show_overlap_enable = true, show_overlap_enable = true,
overlap = 20, overlap = 20,
@ -152,36 +173,36 @@ function ReaderRolling:onReadSettings(config)
self.show_overlap_enable = soe self.show_overlap_enable = soe
end end
local last_xp = config:readSetting("last_xpointer") local last_xp = config:readSetting("last_xpointer")
local last_per = config:readSetting("last_percent")
if last_xp then if last_xp then
table.insert(self.ui.postInitCallback, function() table.insert(self.ui.postInitCallback, function()
self:gotoXPointer(last_xp) self.xpointer = last_xp
self:gotoXPointer(self.xpointer)
-- we have to do a real jump in self.ui.document._document to -- we have to do a real jump in self.ui.document._document to
-- update status information in CREngine. -- update status information in CREngine.
self.ui.document:gotoXPointer(last_xp) self.ui.document:gotoXPointer(self.xpointer)
end) end)
end
-- we read last_percent just for backward compatibility -- we read last_percent just for backward compatibility
if not last_xp then elseif last_per then
local last_per = config:readSetting("last_percent") table.insert(self.ui.postInitCallback, function()
if last_per then self:gotoPercent(last_per)
table.insert(self.ui.postInitCallback, function() -- we have to do a real pos change in self.ui.document._document
self:gotoPercent(last_per) -- to update status information in CREngine.
-- we have to do a real pos change in self.ui.document._document self.ui.document:gotoPos(self.current_pos)
-- to update status information in CREngine. self.xpointer = self.ui.document:getXPointer()
self.ui.document:gotoPos(self.current_pos) end)
end) else
if self.view.view_mode == "page" then
self.ui:handleEvent(Event:new("PageUpdate", 1))
end end
self.xpointer = self.ui.document:getXPointer()
end end
if self.view.view_mode == "page" then
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage()))
end
self.ui:handleEvent(Event:new("UpdatePos"))
end end
function ReaderRolling:onSaveSettings() function ReaderRolling:onSaveSettings()
-- remove last_percent config since its deprecated -- remove last_percent config since its deprecated
self.ui.doc_settings:saveSetting("last_percent", nil) self.ui.doc_settings:saveSetting("last_percent", nil)
self.ui.doc_settings:saveSetting("last_xpointer", self.ui.document:getXPointer()) self.ui.doc_settings:saveSetting("last_xpointer", self.xpointer)
self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent()) self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent())
end end
@ -247,7 +268,8 @@ function ReaderRolling:onResume()
end end
function ReaderRolling:onDoubleTapForward() function ReaderRolling:onDoubleTapForward()
local pageno = self.current_page + self.ui.document:getVisiblePageCount() local visible_page_count = self.ui.document:getVisiblePageCount()
local pageno = self.current_page + (visible_page_count > 1 and 1 or 0)
self:onGotoPage(self.ui.toc:getNextChapter(pageno, 0)) self:onGotoPage(self.ui.toc:getNextChapter(pageno, 0))
return true return true
end end
@ -268,6 +290,14 @@ function ReaderRolling:onGotoPercent(percent)
return true return true
end end
function ReaderRolling:onGotoPage(number)
if number then
self:gotoPage(number)
end
self.xpointer = self.ui.document:getXPointer()
return true
end
function ReaderRolling:onGotoViewRel(diff) function ReaderRolling:onGotoViewRel(diff)
DEBUG("goto relative screen:", diff, ", in mode: ", self.view.view_mode) DEBUG("goto relative screen:", diff, ", in mode: ", self.view.view_mode)
if self.view.view_mode == "scroll" then if self.view.view_mode == "scroll" then
@ -284,6 +314,7 @@ function ReaderRolling:onGotoViewRel(diff)
local page_count = self.ui.document:getVisiblePageCount() local page_count = self.ui.document:getVisiblePageCount()
self:gotoPage(self.current_page + diff*page_count) self:gotoPage(self.current_page + diff*page_count)
end end
self.xpointer = self.ui.document:getXPointer()
return true return true
end end
@ -292,6 +323,7 @@ function ReaderRolling:onPanning(args, key)
local _, dy = unpack(args) local _, dy = unpack(args)
DEBUG("key =", key) DEBUG("key =", key)
self:gotoPos(self.current_pos + dy * self.panning_steps.normal) self:gotoPos(self.current_pos + dy * self.panning_steps.normal)
self.xpointer = self.ui.document:getXPointer()
return true return true
end end
@ -303,6 +335,7 @@ end
--[[ --[[
remember to signal this event when the document has been zoomed, remember to signal this event when the document has been zoomed,
font has been changed, or line height has been changed. font has been changed, or line height has been changed.
Note that xpointer should not be changed.
--]] --]]
function ReaderRolling:onUpdatePos() function ReaderRolling:onUpdatePos()
UIManager:scheduleIn(0.1, function () self:updatePos() end) UIManager:scheduleIn(0.1, function () self:updatePos() end)
@ -316,7 +349,7 @@ function ReaderRolling:updatePos()
local new_height = self.ui.document.info.doc_height local new_height = self.ui.document.info.doc_height
local new_page = self.ui.document.info.number_of_pages local new_page = self.ui.document.info.number_of_pages
if self.old_doc_height ~= new_height or self.old_page ~= new_page then if self.old_doc_height ~= new_height or self.old_page ~= new_page then
self:gotoXPointer(self.ui.document:getXPointer()) self:gotoXPointer(self.xpointer)
self.old_doc_height = new_height self.old_doc_height = new_height
self.old_page = new_page self.old_page = new_page
self.ui:handleEvent(Event:new("UpdateToc")) self.ui:handleEvent(Event:new("UpdateToc"))
@ -324,6 +357,7 @@ function ReaderRolling:updatePos()
UIManager.repaint_all = true UIManager.repaint_all = true
end end
-- FIXME: there should no other way to update xpointer
function ReaderRolling:onUpdateXPointer() function ReaderRolling:onUpdateXPointer()
local xp = self.ui.document:getXPointer() local xp = self.ui.document:getXPointer()
if self.view.view_mode == "page" then if self.view.view_mode == "page" then
@ -334,16 +368,20 @@ function ReaderRolling:onUpdateXPointer()
return true return true
end end
--[[
switching screen mode should not change current page number
--]]
function ReaderRolling:onChangeViewMode() function ReaderRolling:onChangeViewMode()
self.ui.document:_readMetadata() self.ui.document:_readMetadata()
self.old_doc_height = self.ui.document.info.doc_height self.old_doc_height = self.ui.document.info.doc_height
self.old_page = self.ui.document.info.number_of_pages self.old_page = self.ui.document.info.number_of_pages
self.ui:handleEvent(Event:new("UpdateToc")) self.ui:handleEvent(Event:new("UpdateToc"))
self:gotoXPointer(self.ui.document:getXPointer()) if self.xpointer then
if self.view.view_mode == "scroll" then self:gotoXPointer(self.xpointer)
self.current_pos = self.ui.document:getCurrentPos()
else else
self.current_page = self.ui.document:getCurrentPage() table.insert(self.ui.postInitCallback, function()
self:gotoXPointer(self.xpointer)
end)
end end
return true return true
end end
@ -357,15 +395,17 @@ function ReaderRolling:onRedrawCurrentView()
return true return true
end end
function ReaderRolling:onSetDimensions() function ReaderRolling:onSetDimensions(dimen)
-- update listening according to new screen dimen -- update listening according to new screen dimen
if Device:isTouchDevice() then if Device:isTouchDevice() then
self:initGesListener() self:initGesListener()
end end
self.ui.document:setViewDimen(Screen:getSize())
end end
function ReaderRolling:onChangeScreenMode(mode) function ReaderRolling:onChangeScreenMode(mode)
self.ui:handleEvent(Event:new("SetScreenMode", mode)) self.ui:handleEvent(Event:new("SetScreenMode", mode))
self.ui.document:setViewDimen(Screen:getSize())
self:onChangeViewMode() self:onChangeViewMode()
self:onUpdatePos() self:onUpdatePos()
end end
@ -392,6 +432,10 @@ function ReaderRolling:gotoPos(new_pos)
self.ui:handleEvent(Event:new("PosUpdate", new_pos)) self.ui:handleEvent(Event:new("PosUpdate", new_pos))
end end
function ReaderRolling:gotoPercent(new_percent)
self:gotoPos(new_percent * self.doc_height / 10000)
end
function ReaderRolling:gotoPage(new_page) function ReaderRolling:gotoPage(new_page)
self.ui.document:gotoPage(new_page) self.ui.document:gotoPage(new_page)
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage())) self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage()))
@ -405,17 +449,6 @@ function ReaderRolling:gotoXPointer(xpointer)
end end
end end
function ReaderRolling:gotoPercent(new_percent)
self:gotoPos(new_percent * self.doc_height / 10000)
end
function ReaderRolling:onGotoPage(number)
if number then
self:gotoPage(number)
end
return true
end
--[[ --[[
currently we don't need to get page links on each page/pos update currently we don't need to get page links on each page/pos update
since we can check link on the fly when tapping on the screen since we can check link on the fly when tapping on the screen

View File

@ -53,6 +53,7 @@ end
function ReaderToc:onUpdateToc() function ReaderToc:onUpdateToc()
self.toc = nil self.toc = nil
self.ticks = {}
return true return true
end end

View File

@ -330,6 +330,11 @@ function CreDocument:setViewMode(new_mode)
end end
end end
function CreDocument:setViewDimen(dimen)
DEBUG("CreDocument: set view dimen", dimen)
self._document:setViewDimen(dimen.w, dimen.h)
end
function CreDocument:setHeaderFont(new_font) function CreDocument:setHeaderFont(new_font)
if new_font then if new_font then
DEBUG("CreDocument: set header font", new_font) DEBUG("CreDocument: set header font", new_font)

View File

@ -0,0 +1,109 @@
require("commonrequire")
local DocumentRegistry = require("document/documentregistry")
local ReaderUI = require("apps/reader/readerui")
local Event = require("ui/event")
local DEBUG = require("dbg")
describe("Readerrolling module", function()
local sample_epub = "spec/front/unit/data/juliet.epub"
local readerui = ReaderUI:new{
document = DocumentRegistry:openDocument(sample_epub),
}
local rolling = readerui.rolling
describe("test in portrait screen mode", function()
it("should goto portrait screen mode", function()
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
end)
it("should goto certain page", function()
for i = 1, 10, 5 do
rolling:gotoPage(i)
assert.are.same(i, rolling.current_page)
end
end)
it("should goto relative page", function()
for i = 20, 40, 5 do
rolling:gotoPage(i)
rolling:onGotoViewRel(1)
assert.are.same(i + 1, rolling.current_page)
rolling:onGotoViewRel(-1)
assert.are.same(i, rolling.current_page)
end
end)
it("should goto next chapter", function()
local toc = readerui.toc
for i = 30, 50, 5 do
rolling:gotoPage(i)
rolling:onDoubleTapForward()
assert.are.same(toc:getNextChapter(i, 0), rolling.current_page)
end
end)
it("should goto previous chapter", function()
local toc = readerui.toc
for i = 60, 80, 5 do
rolling:gotoPage(i)
rolling:onDoubleTapBackward()
assert.are.same(toc:getPreviousChapter(i, 0), rolling.current_page)
end
end)
end)
describe("test in landscape screen mode", function()
it("should go to landscape screen mode", function()
readerui:handleEvent(Event:new("ChangeScreenMode", "landscape"))
end)
it("should goto certain page", function()
for i = 1, 10, 5 do
rolling:gotoPage(i)
assert.are.same(i, rolling.current_page)
end
end)
it("should goto relative page", function()
for i = 20, 40, 5 do
rolling:gotoPage(i)
rolling:onGotoViewRel(1)
assert.are.same(i + 1, rolling.current_page)
rolling:onGotoViewRel(-1)
assert.are.same(i, rolling.current_page)
end
end)
it("should goto next chapter", function()
local toc = readerui.toc
for i = 30, 50, 5 do
rolling:gotoPage(i)
rolling:onDoubleTapForward()
assert.are.same(toc:getNextChapter(i, 0), rolling.current_page)
end
end)
it("should goto previous chapter", function()
local toc = readerui.toc
for i = 60, 80, 5 do
rolling:gotoPage(i)
rolling:onDoubleTapBackward()
assert.are.same(toc:getPreviousChapter(i, 0), rolling.current_page)
end
end)
end)
describe("switching screen mode should not change current page number", function()
it("for portrait-landscape-portrait switching", function()
for i = 80, 100, 10 do
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
rolling:onGotoPage(i)
assert.are.same(i, rolling.current_page)
readerui:handleEvent(Event:new("ChangeScreenMode", "landscape"))
assert.are_not.same(i, rolling.current_page)
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
assert.are.same(i, rolling.current_page)
end
end)
it("for landscape-portrait-landscape switching", function()
for i = 110, 130, 10 do
readerui:handleEvent(Event:new("ChangeScreenMode", "landscape"))
rolling:onGotoPage(i)
assert.are.same(i, rolling.current_page)
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
assert.are_not.same(i, rolling.current_page)
readerui:handleEvent(Event:new("ChangeScreenMode", "landscape"))
assert.are.same(i, rolling.current_page)
end
end)
end)
end)