refactoring readertoc and readerfooter

so that they don't repeat themselves.
pull/966/head
chrox 10 years ago
parent 50c33b55df
commit b09bb87d4e

@ -20,6 +20,7 @@ local ReaderFooter = InputContainer:new{
visible = true, visible = true,
pageno = nil, pageno = nil,
pages = nil, pages = nil,
toc_level = 0,
progress_percentage = 0.0, progress_percentage = 0.0,
progress_text = nil, progress_text = nil,
text_font_face = "ffont", text_font_face = "ffont",
@ -37,35 +38,39 @@ function ReaderFooter:init()
self.pageno = self.view.state.page self.pageno = self.view.state.page
self.pages = self.view.document:getPageCount() self.pages = self.view.document:getPageCount()
local progress_text_default = "" local text_default = ""
if DMINIBAR_ALL_AT_ONCE then if DMINIBAR_ALL_AT_ONCE then
local info = {}
if DMINIBAR_BATTERY then
table.insert(info, "B:100%")
end
if DMINIBAR_TIME then if DMINIBAR_TIME then
progress_text_default = progress_text_default .. " | WW:WW" table.insert(info, "WW:WW")
end end
if DMINIBAR_PAGES then if DMINIBAR_PAGES then
progress_text_default = progress_text_default .. " | 0000 / 0000" table.insert(info, "0000 / 0000")
end end
if DMINIBAR_NEXT_CHAPTER then if DMINIBAR_NEXT_CHAPTER then
progress_text_default = progress_text_default .. " | => 000" table.insert(info, "=> 000")
end end
if DMINIBAR_BATTERY then text_default = table.concat(info, " | ")
progress_text_default = progress_text_default .. " | B:100%"
end
progress_text_default = string.sub(progress_text_default, 4)
else else
progress_text_default = string.format(" %d / %d ", self.pages, self.pages) text_default = string.format(" %d / %d ", self.pages, self.pages)
end end
self.progress_text = TextWidget:new{ self.progress_text = TextWidget:new{
text = progress_text_default, text = text_default,
face = Font:getFace(self.text_font_face, self.text_font_size), face = Font:getFace(self.text_font_face, self.text_font_size),
} }
local text_width = self.progress_text:getSize().w local text_width = self.progress_text:getSize().w
local ticks = (self.ui.toc and DMINIBAR_PROGRESS_MARKER)
and self.ui.toc:getTocTicks(self.toc_level) or {}
self.progress_bar = ProgressWidget:new{ self.progress_bar = ProgressWidget:new{
width = math.floor(Screen:getWidth() - text_width - self.padding), width = math.floor(Screen:getWidth() - text_width - self.padding),
height = self.bar_height, height = self.bar_height,
percentage = self.progress_percentage, percentage = self.progress_percentage,
TOC = self.ui.document:getToc(), ticks = ticks,
tick_width = DMINIBAR_TOC_MARKER_WIDTH,
last = self.pages, last = self.pages,
} }
local horizontal_group = HorizontalGroup:new{} local horizontal_group = HorizontalGroup:new{}
@ -121,42 +126,55 @@ function ReaderFooter:init()
self:applyFooterMode() self:applyFooterMode()
end end
function ReaderFooter:fillToc() function ReaderFooter:getBatteryInfo()
self.toc = self.ui.document:getToc() local powerd = Device:getPowerDevice()
--local state = powerd:isCharging() and -1 or powerd:getCapacity()
return "B:" .. powerd:getCapacity() .. "%"
end
function ReaderFooter:getTimeInfo()
return os.date("%H:%M")
end
function ReaderFooter:getProgressInfo()
return string.format("%d / %d", self.pageno, self.pages)
end
function ReaderFooter:getNextChapterInfo()
local left = self.ui.toc:getChapterPagesLeft(self.pageno, self.toc_level)
return "=> " .. (left and left or self.pages - self.pageno)
end end
function ReaderFooter:updateFooterPage() function ReaderFooter:updateFooterPage()
if type(self.pageno) ~= "number" then return end if type(self.pageno) ~= "number" then return end
self.progress_bar.percentage = self.pageno / self.pages self.progress_bar.percentage = self.pageno / self.pages
if DMINIBAR_ALL_AT_ONCE then if DMINIBAR_ALL_AT_ONCE then
self.progress_text.text = "" local info = {}
if DMINIBAR_BATTERY then if DMINIBAR_BATTERY then
local powerd = Device:getPowerDevice() table.insert(info, self:getBatteryInfo())
local state = powerd:isCharging() and -1 or powerd:getCapacity()
self.progress_text.text = self.progress_text.text .. " | B:" .. powerd:getCapacity() .. "%"
end end
if DMINIBAR_TIME then if DMINIBAR_TIME then
self.progress_text.text = self.progress_text.text .. " | " .. os.date("%H:%M") table.insert(info, self:getTimeInfo())
end end
if DMINIBAR_PAGES then if DMINIBAR_PAGES then
self.progress_text.text = self.progress_text.text .. " | " .. string.format("%d / %d", self.pageno, self.pages) table.insert(info, self:getProgressInfo())
end end
if DMINIBAR_NEXT_CHAPTER then if DMINIBAR_NEXT_CHAPTER then
self.progress_text.text = self.progress_text.text .. " | => " .. self.ui.toc:_getChapterPagesLeft(self.pageno,self.pages) table.insert(info, self:getNextChapterInfo())
end end
self.progress_text.text = string.sub(self.progress_text.text, 4) self.progress_text.text = table.concat(info, " | ")
else else
local info = ""
if self.mode == 1 then if self.mode == 1 then
self.progress_text.text = string.format("%d / %d", self.pageno, self.pages) info = self:getProgressInfo()
elseif self.mode == 2 then elseif self.mode == 2 then
self.progress_text.text = os.date("%H:%M") info = self:getTimeInfo()
elseif self.mode == 3 then elseif self.mode == 3 then
self.progress_text.text = "=> " .. self.ui.toc:_getChapterPagesLeft(self.pageno,self.pages) info = self:getNextChapterInfo()
elseif self.mode == 4 then elseif self.mode == 4 then
local powerd = Device:getPowerDevice() info = self:getBatteryInfo()
local state = powerd:isCharging() and -1 or powerd:getCapacity()
self.progress_text.text = "B:" .. powerd:getCapacity() .. "%"
end end
self.progress_text.text = info
end end
end end
@ -166,9 +184,10 @@ function ReaderFooter:updateFooterPos()
self.progress_bar.percentage = self.position / self.doc_height self.progress_bar.percentage = self.position / self.doc_height
if self.show_time then if self.show_time then
self.progress_text.text = os.date("%H:%M") self.progress_text.text = self:getTimeInfo()
else else
self.progress_text.text = string.format("%1.f", self.progress_bar.percentage*100).."%" local percentage = self.progress_bar.percentage
self.progress_text.text = string.format("%1.f", percentage*100) .. "%"
end end
end end

@ -247,18 +247,12 @@ function ReaderRolling:onResume()
end end
function ReaderRolling:onDoubleTapForward() function ReaderRolling:onDoubleTapForward()
local i = self.ui.toc:_getNextChapter(self.current_page+self.ui.document:getVisiblePageCount()) self:onGotoPage(self.ui.toc:getNextChapter(self.current_page))
if i ~= "" then
self:onGotoPage(i)
end
return true return true
end end
function ReaderRolling:onDoubleTapBackward() function ReaderRolling:onDoubleTapBackward()
local i = self.ui.toc:_getPreviousChapter(self.current_page) self:onGotoPage(self.ui.toc:getPreviousChapter(self.current_page))
if i ~= "" then
self:onGotoPage(i)
end
return true return true
end end
@ -414,7 +408,9 @@ function ReaderRolling:gotoPercent(new_percent)
end end
function ReaderRolling:onGotoPage(number) function ReaderRolling:onGotoPage(number)
self:gotoPage(number) if number then
self:gotoPage(number)
end
return true return true
end end

@ -13,6 +13,7 @@ local _ = require("gettext")
local ReaderToc = InputContainer:new{ local ReaderToc = InputContainer:new{
toc = nil, toc = nil,
ticks = {},
toc_menu_title = _("Table of contents"), toc_menu_title = _("Table of contents"),
} }
@ -60,30 +61,17 @@ function ReaderToc:onPageUpdate(pageno)
end end
function ReaderToc:fillToc() function ReaderToc:fillToc()
if self.toc and #self.toc > 0 then return end
self.toc = self.ui.document:getToc() self.toc = self.ui.document:getToc()
end end
-- _getTocTitleByPage wrapper, so specific reader
-- can tranform pageno according its need
function ReaderToc:getTocTitleByPage(pn_or_xp) function ReaderToc:getTocTitleByPage(pn_or_xp)
local page = pn_or_xp self:fillToc()
if #self.toc == 0 then return "" end
local pageno = pn_or_xp
if type(pn_or_xp) == "string" then if type(pn_or_xp) == "string" then
page = self.ui.document:getPageFromXPointer(pn_or_xp) pageno = self.ui.document:getPageFromXPointer(pn_or_xp)
end end
return self:_getTocTitleByPage(page)
end
function ReaderToc:_getTocTitleByPage(pageno)
if not self.toc then
-- build toc when needed.
self:fillToc()
end
-- no table of content
if #self.toc == 0 then
return ""
end
local pre_entry = self.toc[1] local pre_entry = self.toc[1]
for _k,_v in ipairs(self.toc) do for _k,_v in ipairs(self.toc) do
if _v.page > pageno then if _v.page > pageno then
@ -98,135 +86,91 @@ function ReaderToc:getTocTitleOfCurrentPage()
return self:getTocTitleByPage(self.pageno) return self:getTocTitleByPage(self.pageno)
end end
function ReaderToc:_getChapterPagesLeft(pageno,pages) function ReaderToc:getMaxDepth()
local i self:fillToc()
local j = 0 local max_depth = 0
for _, v in ipairs(self.toc) do
if not self.toc then if v.depth > max_depth then
-- build toc when needed. max_depth = v.depth
self:fillToc()
end
-- no table of content
if #self.toc == 0 then
return ""
end
if #self.toc > 0 then
for i = 1, #self.toc do
v = self.toc[i]
if v.page > pageno then
j = v.page
break
end
end end
end end
if j == 0 then return max_depth
if pages > 0 then
return pages-pageno
else
return ""
end
else
return j-pageno-1
end
end end
function ReaderToc:_getChapterPagesDone(pageno) --[[
local i TOC ticks is a list of page number in ascending order of TOC nodes at certain level
local j = 0 positive level counts nodes of the depth level (level 1 for depth 1)
non-positive level counts nodes of reversed depth level (level -1 for max_depth-1)
if not self.toc then --]]
-- build toc when needed. function ReaderToc:getTocTicks(level)
self:fillToc() if self.ticks[level] then return self.ticks[level] end
end -- build toc ticks if not found
self:fillToc()
-- no table of content local ticks = {}
if #self.toc == 0 then
return ""
end
if #self.toc > 0 then if #self.toc > 0 then
for i = 1, #self.toc do local depth = nil
v = self.toc[i] if level > 0 then
if v.page >= pageno then depth = level
break else
depth = self:getMaxDepth() + level
end
for _, v in ipairs(self.toc) do
if v.depth == depth then
table.insert(ticks, v.page)
end end
j = v.page
end end
-- normally the ticks are sorted already but in rare cases
-- toc nodes may be not in ascending order
table.sort(ticks)
-- cache ticks only if ticks are available
self.ticks[level] = ticks
end end
if j < 2 then return ticks
return ""
else
return j-pageno
end
end end
function ReaderToc:_getPreviousChapter(pageno) function ReaderToc:getNextChapter(cur_pageno, level)
local i local ticks = self:getTocTicks(level)
local j = 0 local next_chapter = nil
for i = 1, #ticks do
if not self.toc then if ticks[i] > cur_pageno then
-- build toc when needed. next_chapter = ticks[i]
self:fillToc() break
end
-- no table of content
if #self.toc == 0 then
return ""
end
if #self.toc > 0 then
for i = 1, #self.toc do
v = self.toc[i]
if v.page >= pageno then
break
end
j = v.page
end end
end end
if j >= pageno then return next_chapter
return ""
else
return j
end
end end
function ReaderToc:_getNextChapter(pageno) function ReaderToc:getPreviousChapter(cur_pageno, level)
local i local ticks = self:getTocTicks(level)
local j = 0 local previous_chapter = nil
for i = 1, #ticks do
if not self.toc then if ticks[i] >= cur_pageno then
-- build toc when needed. break
self:fillToc() end
previous_chapter = ticks[i]
end end
return previous_chapter
end
-- no table of content function ReaderToc:getChapterPagesLeft(pageno, level)
if #self.toc == 0 then local next_chapter = self:getNextChapter(pageno, level)
return "" if next_chapter then
next_chapter = next_chapter - pageno
end end
return next_chapter
end
if #self.toc > 0 then function ReaderToc:getChapterPagesDone(pageno, level)
for i = 1, #self.toc do local previous_chapter = self:getPreviousChapter(pageno, level)
v = self.toc[i] if previous_chapter then
if v.page >= pageno then previous_chapter = pageno - previous_chapter
j = v.page
break
end
end
end
if j < pageno then
return ""
else
return j
end end
return previous_chapter
end end
function ReaderToc:onShowToc() function ReaderToc:onShowToc()
if not self.toc then self:fillToc()
self:fillToc()
end
-- build menu items -- build menu items
if #self.toc > 0 and not self.toc[1].text then if #self.toc > 0 and not self.toc[1].text then
for _,v in ipairs(self.toc) do for _,v in ipairs(self.toc) do

@ -11,12 +11,12 @@ local ProgressWidget = Widget:new{
margin_v = 1, margin_v = 1,
radius = 2, radius = 2,
bordersize = 1, bordersize = 1,
toc_marker_width = DMINIBAR_TOC_MARKER_WIDTH,
bordercolor = 15, bordercolor = 15,
bgcolor = 0, bgcolor = 0,
rectcolor = 10, rectcolor = 10,
percentage = nil, percentage = nil,
TOC = {}, ticks = {},
tick_width = 3,
last = nil, last = nil,
} }
@ -37,14 +37,12 @@ function ProgressWidget:paintTo(bb, x, y)
bb:paintRect(x+self.margin_h, y+self.margin_v+self.bordersize, bb:paintRect(x+self.margin_h, y+self.margin_v+self.bordersize,
(my_size.w-2*self.margin_h)*self.percentage, (my_size.w-2*self.margin_h)*self.percentage,
(my_size.h-2*(self.margin_v+self.bordersize)), self.rectcolor) (my_size.h-2*(self.margin_v+self.bordersize)), self.rectcolor)
if DMINIBAR_PROGRESS_MARKER then for i=1, #self.ticks do
if #self.TOC > 0 then local page = self.ticks[i]
for i=1, #self.TOC do bb:paintRect(
v = self.TOC[i] x + (my_size.w-2*self.margin_h)*(page/self.last),
bb:paintRect(x+(my_size.w-2*self.margin_h)*(v.page/self.last), y+self.margin_v+self.bordersize, y + self.margin_v + self.bordersize, self.tick_width,
self.toc_marker_width,(my_size.h-2*(self.margin_v+self.bordersize)), self.bordercolor) (my_size.h-2*(self.margin_v+self.bordersize)), self.bordercolor)
end
end
end end
end end

@ -0,0 +1,60 @@
require("commonrequire")
local DocumentRegistry = require("document/documentregistry")
local ReaderUI = require("apps/reader/readerui")
local DEBUG = require("dbg")
describe("Readertoc module", function()
local sample_epub = "spec/front/unit/data/juliet.epub"
local readerui = ReaderUI:new{
document = DocumentRegistry:openDocument(sample_epub),
}
local toc = readerui.toc
local toc_max_depth = nil
it("should get max toc depth", function()
toc_max_depth = toc:getMaxDepth()
assert.are.same(2, toc_max_depth)
end)
it("should get toc title from page", function()
local title = toc:getTocTitleByPage(56)
assert(title == "Prologue")
local title = toc:getTocTitleByPage(172)
assert(title == "SCENE IV. Hall in Capulet's house.")
end)
describe("getTocTicks API", function()
local ticks_level_0 = nil
it("should get ticks of level 0", function()
ticks_level_0 = toc:getTocTicks(0)
assert.are.same(26, #ticks_level_0)
end)
local ticks_level_1 = nil
it("should get ticks of level 1", function()
ticks_level_1 = toc:getTocTicks(1)
assert.are.same(7, #ticks_level_1)
end)
local ticks_level_m1 = nil
it("should get ticks of level -1", function()
ticks_level_m1 = toc:getTocTicks(1)
assert.are.same(7, #ticks_level_m1)
end)
it("should get the same ticks of level -1 and level 1", function()
if toc_max_depth == 2 then
assert.are.same(ticks_level_1, ticks_level_m1)
end
end)
end)
it("should get page of next chapter", function()
assert.are.same(25, toc:getNextChapter(10, 0))
assert.are.same(103, toc:getNextChapter(100, 0))
assert.are.same(nil, toc:getNextChapter(200, 0))
end)
it("should get page of previous chapter", function()
assert.are.same(9, toc:getPreviousChapter(10, 0))
assert.are.same(95, toc:getPreviousChapter(100, 0))
assert.are.same(190, toc:getPreviousChapter(200, 0))
end)
it("should get page left of chapter", function()
assert.are.same(15, toc:getChapterPagesLeft(10, 0))
assert.are.same(3, toc:getChapterPagesLeft(100, 0))
assert.are.same(nil, toc:getChapterPagesLeft(200, 0))
end)
end)
Loading…
Cancel
Save