refactor: use new KeyValuePage widget for displaying statistics

pull/1817/head
Qingping Hou 8 years ago
parent 65455cee23
commit 11ee8d6fcc

@ -71,7 +71,7 @@ script:
- make all - make all
- travis_retry make testfront - travis_retry make testfront
- luajit $(which luacheck) --no-color -q frontend | tee ./luacheck.out - luajit $(which luacheck) --no-color -q frontend | tee ./luacheck.out
- test $(grep Total ./luacheck.out | awk '{print $2}') -le 238 - test $(grep Total ./luacheck.out | awk '{print $2}') -le 220
after_success: after_success:
- make coverage - make coverage

@ -22,6 +22,10 @@ function DataStorage:getDataDir()
return data_dir return data_dir
end end
function DataStorage:getHistoryDir()
return self:getDataDir() .. "/history"
end
local function initDataDir() local function initDataDir()
local data_dir = DataStorage:getDataDir() local data_dir = DataStorage:getDataDir()
local sub_data_dirs = {"cache", "clipboard", "data", "history", "ota", "screenshots"} local sub_data_dirs = {"cache", "clipboard", "data", "history", "ota", "screenshots"}

@ -6,10 +6,11 @@ local DataStorage = require("datastorage")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local DocSettings = require("docsettings") local DocSettings = require("docsettings")
local Menu = require("ui/widget/menu") local Menu = require("ui/widget/menu")
local joinPath = require("ffi/util").joinPath
local Screen = require("device").screen local Screen = require("device").screen
local _ = require("gettext") local _ = require("gettext")
local history_dir = DataStorage:getDataDir() .. "/history/" local history_dir = DataStorage:getHistoryDir()
local FileManagerHistory = InputContainer:extend{ local FileManagerHistory = InputContainer:extend{
hist_menu_title = _("History"), hist_menu_title = _("History"),
@ -30,7 +31,7 @@ function FileManagerHistory:onMenuHold(item)
{ {
text = _("Remove this item from history"), text = _("Remove this item from history"),
callback = function() callback = function()
os.remove(history_dir..item.histfile) os.remove(joinPath(history_dir, item.histfile))
self._manager:updateItemTable() self._manager:updateItemTable()
UIManager:close(self.histfile_dialog) UIManager:close(self.histfile_dialog)
end, end,
@ -82,7 +83,7 @@ function FileManagerHistory:updateItemTable()
self.hist = {} self.hist = {}
for f in lfs.dir(history_dir) do for f in lfs.dir(history_dir) do
local path = history_dir..f local path = joinPath(history_dir, f)
if lfs.attributes(path, "mode") == "file" then if lfs.attributes(path, "mode") == "file" then
local name = DocSettings:getNameFromHistory(f) local name = DocSettings:getNameFromHistory(f)
table.insert(self.hist, { table.insert(self.hist, {

@ -12,7 +12,6 @@ local BBoxWidget = require("ui/widget/bboxwidget")
local HorizontalSpan = require("ui/widget/horizontalspan") local HorizontalSpan = require("ui/widget/horizontalspan")
local Button = require("ui/widget/button") local Button = require("ui/widget/button")
local Math = require("optmath") local Math = require("optmath")
local DEBUG = require("dbg")
local Blitbuffer = require("ffi/blitbuffer") local Blitbuffer = require("ffi/blitbuffer")
local PageCropDialog = VerticalGroup:new{ local PageCropDialog = VerticalGroup:new{

@ -2,7 +2,6 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local RightContainer = require("ui/widget/container/rightcontainer") local RightContainer = require("ui/widget/container/rightcontainer")
local ImageWidget = require("ui/widget/imagewidget") local ImageWidget = require("ui/widget/imagewidget")
local GestureRange = require("ui/gesturerange") local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("device") local Device = require("device")
local Geom = require("ui/geometry") local Geom = require("ui/geometry")
local Screen = require("device").screen local Screen = require("device").screen

@ -8,7 +8,6 @@ local Screen = require("device").screen
local Input = require("device").input local Input = require("device").input
local Event = require("ui/event") local Event = require("ui/event")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local DEBUG = require("dbg")
local T = require("ffi/util").template local T = require("ffi/util").template
local _ = require("gettext") local _ = require("gettext")

@ -14,7 +14,6 @@ local Screen = require("device").screen
local Geom = require("ui/geometry") local Geom = require("ui/geometry")
local Event = require("ui/event") local Event = require("ui/event")
local Font = require("ui/font") local Font = require("ui/font")
local DEBUG = require("dbg")
local _ = require("gettext") local _ = require("gettext")
local util = require("util") local util = require("util")
@ -54,7 +53,7 @@ function ReaderFooter:init()
book_time_to_read = true, book_time_to_read = true,
chapter_time_to_read = true, chapter_time_to_read = true,
} }
local text_default = "" local text_default
if self.settings.all_at_once then if self.settings.all_at_once then
local info = {} local info = {}
if self.settings.battery then if self.settings.battery then

@ -1,5 +1,6 @@
local InputContainer = require("ui/widget/container/inputcontainer") local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local JSON = require("json")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local T = require("ffi/util").template local T = require("ffi/util").template
local _ = require("gettext") local _ = require("gettext")
@ -11,32 +12,35 @@ local ReaderHyphenation = InputContainer:new{
} }
function ReaderHyphenation:init() function ReaderHyphenation:init()
local lang_data_file = assert(io.open("./data/hyph/languages.json"), "r")
lang_data = json.decode(lang_data_file:read("*all"))
self.lang_table = {} self.lang_table = {}
self.hyph_table = {} self.hyph_table = {}
self.hyph_alg = cre.getSelectedHyphDict() self.hyph_alg = cre.getSelectedHyphDict()
for k,v in ipairs(lang_data) do
table.insert(self.hyph_table, {
text = v.name,
callback = function()
self.hyph_alg = v.filename
UIManager:show(InfoMessage:new{
text = T( _("Changed hyphenation to %1."), v.name),
})
self.ui.document:setHyphDictionary(v.filename)
self.ui.toc:onUpdateToc()
end,
checked_func = function()
return v.filename == self.hyph_alg
end
})
self.lang_table[v.language] = v.filename local lang_data_file = assert(io.open("./data/hyph/languages.json"), "r")
if v.aliases then local ok, lang_data = pcall(JSON.decode, lang_data_file:read("*all"))
for i,alias in ipairs(v.aliases) do
self.lang_table[alias] = v.filename if ok and lang_data then
for k,v in ipairs(lang_data) do
table.insert(self.hyph_table, {
text = v.name,
callback = function()
self.hyph_alg = v.filename
UIManager:show(InfoMessage:new{
text = T(_("Changed hyphenation to %1."), v.name),
})
self.ui.document:setHyphDictionary(v.filename)
self.ui.toc:onUpdateToc()
end,
checked_func = function()
return v.filename == self.hyph_alg
end
})
self.lang_table[v.language] = v.filename
if v.aliases then
for i,alias in ipairs(v.aliases) do
self.lang_table[alias] = v.filename
end
end end
end end
end end

@ -6,7 +6,6 @@ local Geom = require("ui/geometry")
local Screen = require("device").screen local Screen = require("device").screen
local Device = require("device") local Device = require("device")
local Event = require("ui/event") local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext") local _ = require("gettext")
local ReaderLink = InputContainer:new{ local ReaderLink = InputContainer:new{

@ -318,17 +318,9 @@ function ReaderPaging:onSwipe(arg, ges)
elseif self.page_flipping_mode and self.original_page then elseif self.page_flipping_mode and self.original_page then
self:gotoPage(self.original_page) self:gotoPage(self.original_page)
elseif ges.direction == "west" then elseif ges.direction == "west" then
if DCHANGE_WEST_SWIPE_TO_EAST then self:onPagingRel(1)
self:onPagingRel(-1)
else
self:onPagingRel(1)
end
elseif ges.direction == "east" then elseif ges.direction == "east" then
if DCHANGE_EAST_SWIPE_TO_WEST then self:onPagingRel(-1)
self:onPagingRel(1)
else
self:onPagingRel(-1)
end
else else
-- trigger full refresh -- trigger full refresh
UIManager:setDirty(nil, "full") UIManager:setDirty(nil, "full")

@ -14,8 +14,7 @@ local ReaderPanning = InputContainer:new{
} }
function ReaderPanning:init() function ReaderPanning:init()
if Device:isTouchDevice() then if Device:hasKeyboard() then
else
self.key_events = { self.key_events = {
-- these will all generate the same event, just with different arguments -- these will all generate the same event, just with different arguments
MoveUp = { MoveUp = {

@ -261,17 +261,9 @@ end
function ReaderRolling:onSwipe(arg, ges) function ReaderRolling:onSwipe(arg, ges)
if ges.direction == "west" or ges.direction == "north" then if ges.direction == "west" or ges.direction == "north" then
if DCHANGE_WEST_SWIPE_TO_EAST then self:onGotoViewRel(1)
self:onGotoViewRel(-1)
else
self:onGotoViewRel(1)
end
elseif ges.direction == "east" or ges.direction == "south" then elseif ges.direction == "east" or ges.direction == "south" then
if DCHANGE_EAST_SWIPE_TO_WEST then self:onGotoViewRel(-1)
self:onGotoViewRel(1)
else
self:onGotoViewRel(-1)
end
end end
end end

@ -424,6 +424,12 @@ function GestureDetector:handleSwipe(tev)
y = self.first_tevs[slot].y, y = self.first_tevs[slot].y,
w = 0, h = 0, w = 0, h = 0,
} }
-- TODO: dirty hack for some weird devices, replace it with better solution
if swipe_direction == "west" and DCHANGE_WEST_SWIPE_TO_EAST then
swipe_direction = "east"
elseif swipe_direction == "east" and DCHANGE_EAST_SWIPE_TO_WEST then
swipe_direction = "west"
end
DEBUG("swipe", swipe_direction, swipe_distance, "detected in slot", slot) DEBUG("swipe", swipe_direction, swipe_distance, "detected in slot", slot)
self:clearState(slot) self:clearState(slot)
return { return {

@ -4,14 +4,14 @@ local dump = require("dump")
local DocSettings = {} local DocSettings = {}
local history_dir = DataStorage:getDataDir() .. "/history/" local history_dir = DataStorage:getHistoryDir()
function DocSettings:getSidecarDir(doc_path) function DocSettings:getSidecarDir(doc_path)
return doc_path:match("(.*)%.")..".sdr" return doc_path:match("(.*)%.")..".sdr"
end end
function DocSettings:getHistoryPath(fullpath) function DocSettings:getHistoryPath(fullpath)
return history_dir .. "[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua" return history_dir .. "/[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua"
end end
function DocSettings:getPathFromHistory(hist_name) function DocSettings:getPathFromHistory(hist_name)

@ -31,9 +31,10 @@ function PdfDocument:init()
else else
self:_readMetadata() self:_readMetadata()
end end
if not (self.info.number_of_pages > 0) then -- TODO: handle this
-- if not (self.info.number_of_pages > 0) then
--error("No page found in PDF file") --error("No page found in PDF file")
end -- end
end end
function PdfDocument:unlock(password) function PdfDocument:unlock(password)

@ -10,6 +10,7 @@ local PicDocument = Document:new{
function PicDocument:init() function PicDocument:init()
if not pic then pic = require("ffi/pic") end if not pic then pic = require("ffi/pic") end
local ok
ok, self._document = pcall(pic.openDocument, self.file) ok, self._document = pcall(pic.openDocument, self.file)
if not ok then if not ok then
error("Failed to open jpeg image") error("Failed to open jpeg image")

@ -11,8 +11,8 @@ local GestureRange = {
scale = nil, scale = nil,
} }
function GestureRange:new(o) function GestureRange:new(from_o)
local o = o or {} local o = from_o or {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
@ -29,7 +29,7 @@ function GestureRange:match(gs)
-- e.g. range = function() return self.dimen end -- e.g. range = function() return self.dimen end
-- for inputcontainer given that the x and y field of `self.dimen` is only -- for inputcontainer given that the x and y field of `self.dimen` is only
-- filled when the inputcontainer is painted into blitbuffer -- filled when the inputcontainer is painted into blitbuffer
local range = nil local range
if type(self.range) == "function" then if type(self.range) == "function" then
range = self.range() range = self.range()
else else

@ -18,7 +18,7 @@ local GlyphCache = Cache:new{
} }
-- iterator over UTF8 encoded characters in a string -- iterator over UTF8 encoded characters in a string
local function utf8Chars(input) local function utf8Chars(input_text)
local function read_next_glyph(input, pos) local function read_next_glyph(input, pos)
if string.len(input) < pos then return nil end if string.len(input) < pos then return nil end
local value = string.byte(input, pos) local value = string.byte(input, pos)
@ -60,7 +60,7 @@ local function utf8Chars(input)
return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left) return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left)
end end
end end
return read_next_glyph, input, 1 return read_next_glyph, input_text, 1
end end
function RenderText:getGlyph(face, charcode, bold) function RenderText:getGlyph(face, charcode, bold)
@ -81,7 +81,7 @@ function RenderText:getGlyph(face, charcode, bold)
rendered_glyph = fb_face.ftface:renderGlyph(charcode, bold) rendered_glyph = fb_face.ftface:renderGlyph(charcode, bold)
--DEBUG("fallback to font", font) --DEBUG("fallback to font", font)
break break
end end
end end
end end
end end

@ -9,7 +9,6 @@ local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry") local Geom = require("ui/geometry")
local Device = require("device") local Device = require("device")
local Font = require("ui/font") local Font = require("ui/font")
local DEBUG = require("dbg")
local _ = require("gettext") local _ = require("gettext")
--[[ --[[

@ -1,14 +1,24 @@
--[[--
Button widget that shows an "×" and handles closing window when tapped
Example:
local parent_widget = HorizontalGroup:new{}
table.insert(parent_widget, CloseButton:new{
window = parent_widget,
})
UIManager:show(parent_widget)
]]
local InputContainer = require("ui/widget/container/inputcontainer") local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer") local FrameContainer = require("ui/widget/container/framecontainer")
local TextWidget = require("ui/widget/textwidget") local TextWidget = require("ui/widget/textwidget")
local GestureRange = require("ui/gesturerange") local GestureRange = require("ui/gesturerange")
local Font = require("ui/font") local Font = require("ui/font")
--[[
a button widget that shows an "×" and handles closing window when tapped
--]]
local CloseButton = InputContainer:new{ local CloseButton = InputContainer:new{
align = "right", overlap_align = "right",
window = nil, window = nil,
} }
@ -23,7 +33,7 @@ function CloseButton:init()
text_widget text_widget
} }
self.dimen = text_widget:getSize():copy() self.dimen = text_widget:getSize()
self.ges_events.Close = { self.ges_events.Close = {
GestureRange:new{ GestureRange:new{

@ -8,11 +8,15 @@ local WidgetContainer = Widget:new()
function WidgetContainer:init() function WidgetContainer:init()
if self.dimen then if self.dimen then
if not self.dimen.w then if self.initDimen then
self.dimen.w = self[1].getSize().w self:initDimen()
end else
if not self.dimen.h then if not self.dimen.w then
self.dimen.h = self[1].getSize().h self.dimen.w = self[1].getSize().w
end
if not self.dimen.h then
self.dimen.h = self[1].getSize().h
end
end end
end end
end end

@ -91,9 +91,7 @@ function DictQuickLookup:init()
}, },
} }
table.insert(self.dict_bar, table.insert(self.dict_bar,
CloseButton:new{ CloseButton:new{ window = self, })
window = self,
})
end end
end end

@ -39,6 +39,8 @@ function HorizontalGroup:paintTo(bb, x, y)
widget:paintTo(bb, x + self._offsets[i].x, y) widget:paintTo(bb, x + self._offsets[i].x, y)
elseif self.align == "bottom" then elseif self.align == "bottom" then
widget:paintTo(bb, x + self._offsets[i].x, y + size.h - self._offsets[i].y) widget:paintTo(bb, x + self._offsets[i].x, y + size.h - self._offsets[i].y)
else
print("[!] invalid alignment for HorizontalGroup", self.align)
end end
end end
end end

@ -0,0 +1,273 @@
--[[--
Widget that presents a multi-page to show key value pairs.
Example:
local Foo = KeyValuePage:new{
title = "Statistics",
kv_pairs = {
{"Current period", "00:00:00"},
-- single or more "-" will generate a solid line
"----------------------------",
{"Page to read", "5"},
{"Time to read", "00:01:00"},
{"Press me", "will invoke the callback",
callback = function() print("hello") end },
},
}
UIManager:show(Foo)
]]
local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local OverlapGroup = require("ui/widget/overlapgroup")
local LeftContainer = require("ui/widget/container/leftcontainer")
local RightContainer = require("ui/widget/container/rightcontainer")
local LineWidget = require("ui/widget/linewidget")
local Blitbuffer = require("ffi/blitbuffer")
local CloseButton = require("ui/widget/closebutton")
local UIManager = require("ui/uimanager")
local TextWidget = require("ui/widget/textwidget")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Font = require("ui/font")
local Device = require("device")
local Screen = Device.screen
local KeyValueTitle = VerticalGroup:new{
kv_page = nil,
title = "",
align = "left",
}
function KeyValueTitle:init()
self.close_button = CloseButton:new{ window = self }
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
text = self.title,
face = Font:getFace("tfont", 26),
},
self.close_button,
})
self.page_cnt = FrameContainer:new{
padding = 4,
margin = 0,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
overlap_offset = {0, -18},
TextWidget:new{
text = "", -- page count
fgcolor = Blitbuffer.COLOR_GREY,
face = Font:getFace("ffont", 16),
},
}
self.title_bottom = OverlapGroup:new{
dimen = { w = self.width, h = Screen:scaleBySize(2) },
LineWidget:new{
dimen = Geom:new{ w = self.width, h = Screen:scaleBySize(2) },
background = Blitbuffer.COLOR_GREY,
style = "solid",
},
self.page_cnt,
}
table.insert(self, self.title_bottom)
table.insert(self, VerticalSpan:new{ width = Screen:scaleBySize(5) })
end
function KeyValueTitle:setPageCount(curr, total)
if total == 1 then
-- remove page count if there is only one page
table.remove(self.title_bottom, 2)
return
end
self.page_cnt[1]:setText(curr .. "/" .. total)
self.page_cnt.overlap_offset[1] = (self.width - self.page_cnt:getSize().w
- self.close_button:getSize().w)
self.title_bottom[2] = self.page_cnt
end
function KeyValueTitle:onClose()
self.kv_page:onClose()
return true
end
local KeyValueItem = InputContainer:new{
key = nil,
value = nil,
cface = Font:getFace("cfont", 24),
width = nil,
height = nil,
}
function KeyValueItem:init()
self.dimen = Geom:new{w = self.width, h = self.height}
if self.callback and Device:isTouchDevice() then
self.ges_events.Tap = {
GestureRange:new{
ges = "tap",
range = self.dimen,
}
}
end
self[1] = OverlapGroup:new{
dimen = self.dimen:copy(),
LeftContainer:new{
dimen = self.dimen:copy(),
TextWidget:new{
text = self.key,
face = self.cface,
}
},
RightContainer:new{
dimen = self.dimen:copy(),
TextWidget:new{
text = self.value,
face = self.cface,
}
}
}
end
function KeyValueItem:onTap()
self.callback()
return true
end
local KeyValuePage = InputContainer:new{
title = "",
width = nil,
height = nil,
-- index for the first item to show
show_page = 1,
}
function KeyValuePage:init()
self.dimen = Geom:new{
w = self.width or Screen:getWidth(),
h = self.height or Screen:getHeight(),
}
if Device:isTouchDevice() then
self.ges_events.Swipe = {
GestureRange:new{
ges = "swipe",
range = self.dimen,
}
}
end
local padding = Screen:scaleBySize(10)
self.item_width = self.dimen.w - 2 * padding
self.item_height = Screen:scaleBySize(30)
-- setup title bar
self.title_bar = KeyValueTitle:new{
title = self.title,
width = self.item_width,
height = self.item_height,
kv_page = self,
}
-- setup main content
self.item_padding = self.item_height / 4
local line_height = self.item_height + 2 * self.item_padding
local content_height = self.dimen.h - self.title_bar:getSize().h
self.items_per_page = math.floor(content_height / line_height)
self.pages = math.ceil(#self.kv_pairs / self.items_per_page)
self.main_content = VerticalGroup:new{}
self:_populateItems()
-- assemble page
self[1] = FrameContainer:new{
height = self.dimen.h,
padding = padding,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
VerticalGroup:new{
self.title_bar,
self.main_content,
},
}
end
function KeyValuePage:nextPage()
local new_page = math.min(self.show_page+1, self.pages)
if new_page > self.show_page then
self.show_page = new_page
self:_populateItems()
end
end
function KeyValuePage:prevPage()
local new_page = math.max(self.show_page-1, 1)
if new_page < self.show_page then
self.show_page = new_page
self:_populateItems()
end
end
-- make sure self.item_padding and self.item_height are set before calling this
function KeyValuePage:_populateItems()
self.main_content:clear()
local idx_offset = (self.show_page - 1) * self.items_per_page
for idx = 1, self.items_per_page do
local entry = self.kv_pairs[idx_offset + idx]
if entry == nil then break end
table.insert(self.main_content,
VerticalSpan:new{ width = self.item_padding })
if type(entry) == "table" then
table.insert(
self.main_content,
KeyValueItem:new{
height = self.item_height,
width = self.item_width,
key = entry[1],
value = entry[2],
callback = entry.callback,
}
)
elseif type(entry) == "string" then
local c = string.sub(entry, 1, 1)
if c == "-" then
table.insert(self.main_content, LineWidget:new{
background = Blitbuffer.COLOR_LIGHT_GREY,
dimen = Geom:new{
w = self.item_width,
h = Screen:scaleBySize(2)
},
style = "solid",
})
end
end
table.insert(self.main_content,
VerticalSpan:new{ width = self.item_padding })
end
self.title_bar:setPageCount(self.show_page, self.pages)
UIManager:setDirty(self, function()
return "ui", self.dimen
end)
end
function KeyValuePage:onSwipe(arg, ges_ev)
if ges_ev.direction == "west" then
self:nextPage()
return true
elseif ges_ev.direction == "east" then
self:prevPage()
return true
end
end
function KeyValuePage:onClose()
UIManager:close(self)
return true
end
return KeyValuePage

@ -19,13 +19,13 @@ function LineWidget:paintTo(bb, x, y)
else else
if self.empty_segments then if self.empty_segments then
bb:paintRect(x, y, bb:paintRect(x, y,
self.empty_segments[1].s, self.empty_segments[1].s,
self.dimen.h, self.dimen.h,
self.background) self.background)
bb:paintRect(x + self.empty_segments[1].e, y, bb:paintRect(x + self.empty_segments[1].e, y,
self.dimen.w - x - self.empty_segments[1].e, self.dimen.w - x - self.empty_segments[1].e,
self.dimen.h, self.dimen.h,
self.background) self.background)
else else
bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.background) bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.background)
end end

@ -8,7 +8,6 @@ local BottomContainer = require("ui/widget/container/bottomcontainer")
local UnderlineContainer = require("ui/widget/container/underlinecontainer") local UnderlineContainer = require("ui/widget/container/underlinecontainer")
local FocusManager = require("ui/widget/focusmanager") local FocusManager = require("ui/widget/focusmanager")
local TextWidget = require("ui/widget/textwidget") local TextWidget = require("ui/widget/textwidget")
local LineWidget = require("ui/widget/linewidget")
local OverlapGroup = require("ui/widget/overlapgroup") local OverlapGroup = require("ui/widget/overlapgroup")
local VerticalSpan = require("ui/widget/verticalspan") local VerticalSpan = require("ui/widget/verticalspan")
local HorizontalSpan = require("ui/widget/horizontalspan") local HorizontalSpan = require("ui/widget/horizontalspan")
@ -82,7 +81,7 @@ NOTICE:
@menu entry must be provided in order to close the menu @menu entry must be provided in order to close the menu
--]] --]]
local MenuCloseButton = InputContainer:new{ local MenuCloseButton = InputContainer:new{
align = "right", overlap_align = "right",
menu = nil, menu = nil,
dimen = Geom:new{}, dimen = Geom:new{},
} }
@ -94,7 +93,10 @@ function MenuCloseButton:init()
} }
local text_size = self[1]:getSize() local text_size = self[1]:getSize()
self.dimen.w, self.dimen.h = text_size.w*2, text_size.h*2 self.dimen = Geom:new{
w = text_size.w*2,
h = text_size.h*2,
}
self.ges_events.Close = { self.ges_events.Close = {
GestureRange:new{ GestureRange:new{
@ -110,45 +112,6 @@ function MenuCloseButton:onClose()
return true return true
end end
--[[
Widget that displays a solid line in menu
--]]
local SeparatorMenuItem = InputContainer:new{
style = "solid",
dimen = nil,
_line_container = nil,
}
function SeparatorMenuItem:init()
self._line_container = CenterContainer:new{
vertical_align = "center",
dimen = Geom:new {
w = self.dimen.w,
h = self.dimen.h
},
HorizontalGroup:new {
align = "center",
OverlapGroup:new {
dimen = Geom:new { w = self.dimen.w, h = Screen:scaleBySize(2) },
LineWidget:new {
style = self.style,
dimen = Geom:new { w = self.dimen.w - 30, h = Screen:scaleBySize(2) },
}
},
}
}
self[1] = FrameContainer:new {
bordersize = 0,
padding = 0,
HorizontalGroup:new {
align = "center",
HorizontalSpan:new { width = 15 },
self._line_container
}
}
end
--[[ --[[
Widget that displays an item for menu Widget that displays an item for menu
--]] --]]
@ -430,7 +393,7 @@ function Menu:init()
-- start to set up widget layout -- -- start to set up widget layout --
----------------------------------- -----------------------------------
self.menu_title = TextWidget:new{ self.menu_title = TextWidget:new{
align = "center", overlap_align = "center",
text = self.title, text = self.title,
face = self.tface, face = self.tface,
} }
@ -578,9 +541,7 @@ function Menu:init()
if Device:isTouchDevice() then if Device:isTouchDevice() then
if self.has_close_button then if self.has_close_button then
table.insert(self.title_bar, table.insert(self.title_bar,
MenuCloseButton:new{ MenuCloseButton:new{ menu = self })
menu = self,
})
end end
-- watch for outer region if it's a self contained widget -- watch for outer region if it's a self contained widget
if self.is_popout then if self.is_popout then
@ -681,27 +642,20 @@ function Menu:updateItems(select_number)
item_shortcut = "Ent" item_shortcut = "Ent"
end end
end end
local item_tmp local item_tmp = MenuItem:new{
if self.item_table[i].text == "-" then show_parent = self.show_parent,
item_tmp = SeparatorMenuItem:new{ state = self.item_table[i].state,
dimen = self.item_dimen:new{ h = Screen:scaleBySize(10) }, state_size = self.state_size or {},
} text = self.item_table[i].text,
else mandatory = self.item_table[i].mandatory,
item_tmp = MenuItem:new{ bold = self.item_table.current == i,
show_parent = self.show_parent, face = self.cface,
state = self.item_table[i].state, dimen = self.item_dimen:new(),
state_size = self.state_size or {}, shortcut = item_shortcut,
text = self.item_table[i].text, shortcut_style = shortcut_style,
mandatory = self.item_table[i].mandatory, table = self.item_table[i],
bold = self.item_table.current == i, menu = self,
face = self.cface, }
dimen = self.item_dimen:new(),
shortcut = item_shortcut,
shortcut_style = shortcut_style,
table = self.item_table[i],
menu = self,
}
end
table.insert(self.item_group, item_tmp) table.insert(self.item_group, item_tmp)
-- this is for focus manager -- this is for focus manager
table.insert(self.layout, {item_tmp}) table.insert(self.layout, {item_tmp})
@ -923,17 +877,9 @@ end
function Menu:onSwipe(arg, ges_ev) function Menu:onSwipe(arg, ges_ev)
if ges_ev.direction == "west" then if ges_ev.direction == "west" then
if DCHANGE_WEST_SWIPE_TO_EAST then self:onNextPage()
self:onPrevPage()
else
self:onNextPage()
end
elseif ges_ev.direction == "east" then elseif ges_ev.direction == "east" then
if DCHANGE_WEST_SWIPE_TO_EAST then self:onPrevPage()
self:onNextPage()
else
self:onPrevPage()
end
end end
end end

@ -22,14 +22,22 @@ function OverlapGroup:getSize()
end end
end end
return self._size
end
function OverlapGroup:initDimen()
self:getSize() -- populate self._size
-- sync self._size with self.dimen, self.dimen has higher priority
if self.dimen.w then if self.dimen.w then
self._size.w = self.dimen.w self._size.w = self.dimen.w
else
self.dimen.w = self._size.w
end end
if self.dimen.h then if self.dimen.h then
self._size.h = self.dimen.h self._size.h = self.dimen.h
else
self.dimen.h = self._size.h
end end
return self._size
end end
function OverlapGroup:paintTo(bb, x, y) function OverlapGroup:paintTo(bb, x, y)
@ -37,10 +45,12 @@ function OverlapGroup:paintTo(bb, x, y)
for i, wget in ipairs(self) do for i, wget in ipairs(self) do
local wget_size = wget:getSize() local wget_size = wget:getSize()
if wget.align == "right" then if wget.overlap_align == "right" then
wget:paintTo(bb, x+size.w-wget_size.w, y) wget:paintTo(bb, x+size.w-wget_size.w, y)
elseif wget.align == "center" then elseif wget.overlap_align == "center" then
wget:paintTo(bb, x+math.floor((size.w-wget_size.w)/2), y) wget:paintTo(bb, x+math.floor((size.w-wget_size.w)/2), y)
elseif wget.overlap_offset then
wget:paintTo(bb, x+wget.overlap_offset[1], y+wget.overlap_offset[2])
else else
-- default to left -- default to left
wget:paintTo(bb, x, y) wget:paintTo(bb, x, y)

@ -25,23 +25,33 @@ local TextWidget = Widget:new{
--self._length = RenderText:renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, true, self.bold) --self._length = RenderText:renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, true, self.bold)
--end --end
function TextWidget:updateSize()
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
if not tsize then
self._length = 0
else
self._length = tsize.x
end
self._height = self.face.size * 1.5
end
function TextWidget:getSize() function TextWidget:getSize()
--if not self._bb then --if not self._bb then
--self:_render() --self:_render()
--end --end
--return { w = self._length, h = self._bb:getHeight() } --return { w = self._length, h = self._bb:getHeight() }
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold) self:updateSize()
if not tsize then
return Geom:new{}
end
self._length = tsize.x
self._height = self.face.size * 1.5
return Geom:new{ return Geom:new{
w = self._length, w = self._length,
h = self._height, h = self._height,
} }
end end
function TextWidget:setText(text)
self.text = text
self:updateSize()
end
function TextWidget:paintTo(bb, x, y) function TextWidget:paintTo(bb, x, y)
--if not self._bb then --if not self._bb then
--self:_render() --self:_render()

@ -94,16 +94,13 @@ function TouchMenuItem:onTapSelect(arg, ges)
end end
if enabled == false then return end if enabled == false then return end
UIManager:scheduleIn(0.0, function() self.item_frame.invert = true
self.item_frame.invert = true UIManager:setDirty(self.show_parent, function()
UIManager:setDirty(self.show_parent, function() return "ui", self.dimen
return "ui", self.dimen
end)
end) end)
-- yield to main UI loop to invert item
UIManager:scheduleIn(0.1, function() UIManager:scheduleIn(0.1, function()
self.menu:onMenuSelect(self.item) self.menu:onMenuSelect(self.item)
end)
UIManager:scheduleIn(0.5, function()
self.item_frame.invert = false self.item_frame.invert = false
UIManager:setDirty(self.show_parent, function() UIManager:setDirty(self.show_parent, function()
return "ui", self.dimen return "ui", self.dimen

@ -1,21 +1,22 @@
local InputContainer = require("ui/widget/container/inputcontainer") local InputContainer = require("ui/widget/container/inputcontainer")
local MultiInputDialog = require("ui/widget/multiinputdialog") local MultiInputDialog = require("ui/widget/multiinputdialog")
local CenterContainer = require("ui/widget/container/centercontainer") local CenterContainer = require("ui/widget/container/centercontainer")
local KeyValuePage = require("ui/widget/keyvaluepage")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local Screen = require("device").screen local Screen = require("device").screen
local Menu = require("ui/widget/menu")
local Font = require("ui/font") local Font = require("ui/font")
local TimeVal = require("ui/timeval") local TimeVal = require("ui/timeval")
local DataStorage = require("datastorage") local DataStorage = require("datastorage")
local lfs = require("libs/libkoreader-lfs") local lfs = require("libs/libkoreader-lfs")
local DEBUG = require("dbg") local DEBUG = require("dbg")
local T = require("ffi/util").template local T = require("ffi/util").template
local joinPath = require("ffi/util").joinPath
local _ = require("gettext") local _ = require("gettext")
local util = require("util") local util = require("util")
local tableutil = require("tableutil") local tableutil = require("tableutil")
local statistics_dir = DataStorage:getDataDir() .. "/statistics/" local statistics_dir = DataStorage:getDataDir() .. "/statistics/"
local history_dir = DataStorage:getDataDir() .. "/history/" local history_dir = DataStorage:getHistoryDir()
local ReaderStatistics = InputContainer:new { local ReaderStatistics = InputContainer:new {
last_time = nil, last_time = nil,
@ -51,37 +52,37 @@ function ReaderStatistics:init()
self.last_time = TimeVal:now() self.last_time = TimeVal:now()
end end
function ReaderStatistics:getBookProperties()
local props = self.view.document:getProps()
if props.title == "No document" or props.title == "" then
-- FIXME: sometimes crengine returns "No document", try one more time
props = self.view.document:getProps()
end
return props
end
function ReaderStatistics:initData(config) function ReaderStatistics:initData(config)
--first execution -- first execution
if self.is_enabled then if self.is_enabled then
local book_properties = self:getBookProperties()
self:savePropertiesInToData(book_properties)
if not self.data then if not self.data then
--first time merge data self.data = { performance_in_pages= {} }
self:inplaceMigration(); self:inplaceMigration(); -- first time merge data
end end
local book_properties = self:getBookProperties()
self.data.title = book_properties.title
self.data.authors = book_properties.authors
self.data.language = book_properties.language
self.data.series = book_properties.series
self.data.pages = self.view.document:getPageCount() self.data.pages = self.view.document:getPageCount()
return return
end end
end end
function ReaderStatistics:addToMainMenu(tab_item_table) function ReaderStatistics:getStatisticEnabledMenuItem()
table.insert(tab_item_table.plugins, {
text = _("Statistics"),
sub_item_table = {
self:getStatisticEnabledMenuTable(),
self:getStatisticSettingsMenuTable(),
self:getStatisticForCurrentBookMenuTable(),
self:getStatisticTotalStatisticMenuTable(),
}
})
end
function ReaderStatistics:getStatisticEnabledMenuTable()
return { return {
text_func = function() text = _("Enabled"),
return _("Enabled")
end,
checked_func = function() return self.is_enabled end, checked_func = function() return self.is_enabled end,
callback = function() callback = function()
-- if was enabled, have to save data to file -- if was enabled, have to save data to file
@ -99,18 +100,6 @@ function ReaderStatistics:getStatisticEnabledMenuTable()
} }
end end
function ReaderStatistics:getStatisticSettingsMenuTable()
return {
text_func = function()
return _("Settings")
end,
checked_func = function() return false end,
callback = function()
self:updateSettings()
end,
}
end
function ReaderStatistics:updateSettings() function ReaderStatistics:updateSettings()
self.settings_dialog = MultiInputDialog:new { self.settings_dialog = MultiInputDialog:new {
title = _("Statistics settings"), title = _("Statistics settings"),
@ -138,9 +127,9 @@ function ReaderStatistics:updateSettings()
{ {
text = _("Apply"), text = _("Apply"),
callback = function() callback = function()
self:saveSettings(MultiInputDialog:getFields())
self.settings_dialog:onClose() self.settings_dialog:onClose()
UIManager:close(self.settings_dialog) UIManager:close(self.settings_dialog)
self:saveSettings(MultiInputDialog:getFields())
end end
}, },
}, },
@ -153,101 +142,74 @@ function ReaderStatistics:updateSettings()
UIManager:show(self.settings_dialog) UIManager:show(self.settings_dialog)
end end
function ReaderStatistics:getStatisticForCurrentBookMenuTable() function ReaderStatistics:addToMainMenu(tab_item_table)
self.status_menu = {} table.insert(tab_item_table.plugins, {
text = _("Statistics"),
local book_status = Menu:new { sub_item_table = {
title = _("Status"), self:getStatisticEnabledMenuItem(),
item_table = self:updateCurrentStat(), {
is_borderless = true, text = _("Settings"),
is_popout = false, callback = function() self:updateSettings() end,
is_enable_shortcut = false, },
width = Screen:getWidth(), {
height = Screen:getHeight(), text = _("Current book"),
cface = Font:getFace("cfont", 20), callback = function()
} UIManager:show(KeyValuePage:new{
title = _("Statistics"),
self.status_menu = CenterContainer:new { kv_pairs = self:getCurrentStat(),
dimen = Screen:getSize(), })
book_status, end
} },
{
book_status.close_callback = function() text = _("All books"),
UIManager:close(self.status_menu) callback = function()
end total_msg, kv_pairs = self:getTotalStat()
UIManager:show(KeyValuePage:new{
book_status.show_parent = self.status_menu title = total_msg,
kv_pairs = kv_pairs,
return { })
text = _("Current"), end
enabled_func = function() return true end, },
checked_func = function() return false end, },
callback = function() })
book_status:swithItemTable(nil, self:updateCurrentStat())
UIManager:show(self.status_menu)
return true
end
}
end end
function ReaderStatistics:getStatisticTotalStatisticMenuTable() function ReaderStatistics:getCurrentStat()
self.total_status = Menu:new { local dates = {}
title = _("Total"), for k, v in pairs(self.data.performance_in_pages) do
item_table = self:updateTotalStat(), dates[os.date("%Y-%m-%d", k)] = ""
is_borderless = true,
is_popout = false,
is_enable_shortcut = false,
width = Screen:getWidth(),
height = Screen:getHeight(),
cface = Font:getFace("cfont", 20),
}
self.total_menu = CenterContainer:new {
dimen = Screen:getSize(),
self.total_status,
}
self.total_status.close_callback = function()
UIManager:close(self.total_menu)
end end
local total_days = util.tableSize(dates)
self.total_status.show_parent = self.total_menu local read_pages = util.tableSize(self.data.performance_in_pages)
local current_page = self.view.state.page -- get current page from the view
local avg_time_per_page = self.data.total_time_in_sec / read_pages
return { return {
text = _("Total"), { _("Current period"), util.secondsToClock(self.current_period, false) },
callback = function() { _("Time to read"), util.secondsToClock((self.data.pages - current_page) * avg_time_per_page, false) },
self.total_status:swithItemTable(nil, self:updateTotalStat()) { _("Total time"), util.secondsToClock(self.data.total_time_in_sec, false) },
UIManager:show(self.total_menu) { _("Total highlights"), self.data.highlights },
return true { _("Total notes"), self.data.notes },
end { _("Total days"), total_days },
{ _("Average time per page"), util.secondsToClock(avg_time_per_page, false) },
{ _("Read pages/Total pages"), read_pages .. "/" .. self.data.pages },
} }
end end
function ReaderStatistics:updateCurrentStat() function generateReadBooksTable(title, dates)
local stats = {} local result = {}
local dates = {} for k, v in tableutil.spairs(dates, function(t, a, b) return t[b].date < t[a].date end) do
table.insert(result, {
for k, v in pairs(self.data.performance_in_pages) do k,
dates[os.date("%Y-%m-%d", k)] = "" T(_("Pages (%1) Time: %2"), v.count, util.secondsToClock(v.read, false))
})
end end
return result
local read_pages = util.tableSize(self.data.performance_in_pages)
local current_page = self.view.state.page --get current page from the view
local average_time_per_page = self.data.total_time_in_sec / read_pages
table.insert(stats, { text = _("Current period"), mandatory = util.secondsToClock(self.current_period, false) })
table.insert(stats, { text = _("Time to read"), mandatory = util.secondsToClock((self.data.pages - current_page) * average_time_per_page, false) })
table.insert(stats, { text = _("Total time"), mandatory = util.secondsToClock(self.data.total_time_in_sec, false) })
table.insert(stats, { text = _("Total highlights"), mandatory = self.data.highlights })
table.insert(stats, { text = _("Total notes"), mandatory = self.data.notes })
table.insert(stats, { text = _("Total days"), mandatory = util.tableSize(dates) })
table.insert(stats, { text = _("Average time per page"), mandatory = util.secondsToClock(average_time_per_page, false) })
table.insert(stats, { text = _("Read pages/Total pages"), mandatory = read_pages .. "/" .. self.data.pages })
return stats
end end
-- For backward compatibility -- For backward compatibility
function ReaderStatistics:getDatesForBookOldFormat(book) function getDatesForBookOldFormat(book)
local dates = {} local dates = {}
for k, v in pairs(book.details) do for k, v in pairs(book.details) do
@ -267,11 +229,10 @@ function ReaderStatistics:getDatesForBookOldFormat(book)
end end
end end
return self:generateReadBooksTable(book.title, dates) return generateReadBooksTable(book.title, dates)
end end
function getDatesForBook(book)
function ReaderStatistics:getDatesForBook(book)
local dates = {} local dates = {}
for k, v in pairs(book.performance_in_pages) do for k, v in pairs(book.performance_in_pages) do
@ -283,107 +244,93 @@ function ReaderStatistics:getDatesForBook(book)
count = 1 count = 1
} }
else else
dates[date_text] = { -- TODO: test this
read = dates[date_text].read + v, local entry = dates[date_text]
count = dates[date_text].count + 1, entry.read = entry.read + v
date = dates[date_text].date entry.count = entry.count + 1
}
end end
end end
return self:generateReadBooksTable(book.title, dates) return generateReadBooksTable(book.title, dates)
end
function ReaderStatistics:generateReadBooksTable(title, dates)
local result = {}
table.insert(result, { text = title })
for k, v in tableutil.spairs(dates, function(t, a, b) return t[b].date < t[a].date end) do
table.insert(result, { text = k, mandatory = T(_("Pages (%1) Time: %2"), v.count, util.secondsToClock(v.read, false)) })
end
return result
end end
function ReaderStatistics:getTotalStat()
local total_stats = {
{
self.data.title,
util.secondsToClock(self.data.total_time_in_sec, false),
callback = function()
UIManager:show(KeyValuePage:new{
title = self.data.title,
kv_pairs = getDatesForBook(self.data),
})
end,
}
}
function ReaderStatistics:updateTotalStat() -- find stats for all other books in history
local total_stats = {} local proceded_titles, total_books_time = self:getStatisticsFromHistory(total_stats)
local total_books_time = 0 total_books_time = total_books_time + self:getOldStatisticsFromDirectory(proceded_titles, total_stats)
local proceded_titles = self:getStatisticsFromHistory(total_stats, total_books_time)
self:getOldStatisticsFromDirectory(proceded_titles, total_stats, total_books_time)
total_books_time = total_books_time + tonumber(self.data.total_time_in_sec) total_books_time = total_books_time + tonumber(self.data.total_time_in_sec)
table.insert(total_stats, 1, { text = _("Total hours read"), mandatory = util.secondsToClock(total_books_time, false) }) return T(_("Total hours read %1"),
table.insert(total_stats, 2, { text = "-" }) util.secondsToClock(total_books_time, false)),
table.insert(total_stats, 3, { total_stats
text = self.data.title,
mandatory = util.secondsToClock(self.data.total_time_in_sec, false),
callback = function()
self.total_status:swithItemTable(nil, self:getDatesForBook(self.data))
UIManager:show(self.total_menu)
return true
end,
})
return total_stats
end end
function ReaderStatistics:getStatisticsFromHistory(total_stats, total_books_time) function ReaderStatistics:getStatisticsFromHistory(total_stats)
local titles = {} local titles = {}
local total_books_time = 0
for curr_file in lfs.dir(history_dir) do for curr_file in lfs.dir(history_dir) do
local path = history_dir .. curr_file local path = joinPath(history_dir, curr_file)
if lfs.attributes(path, "mode") == "file" then if lfs.attributes(path, "mode") == "file" then
local book_result = self:importFromFile(history_dir, curr_file) local book_result = self:importFromFile(history_dir, curr_file)
local book_stats = book_result.stats local book_stats = book_result.stats
if book_stats and book_stats.title ~= self.data.title then if book_stats and book_stats.title ~= self.data.title then
titles[book_stats.title] = true titles[book_stats.title] = true
table.insert(total_stats, { table.insert(total_stats, {
text = book_stats.title, book_stats.title,
mandatory = util.secondsToClock(book_stats.total_time_in_sec, false), util.secondsToClock(book_stats.total_time_in_sec, false),
callback = function() callback = function()
self.total_status:swithItemTable(nil, self:getDatesForBook(book_stats)) UIManager:show(KeyValuePage:new{
UIManager:show(self.total_menu) title = book_stats.title,
return true kv_pairs = getDatesForBook(book_stats),
})
end, end,
}) })
total_books_time = total_books_time + tonumber(book_stats.total_time_in_sec) total_books_time = total_books_time + tonumber(book_stats.total_time_in_sec)
end end
end end
end end
return titles return titles, total_books_time
end end
-- For backward compatibility -- For backward compatibility
function ReaderStatistics:getOldStatisticsFromDirectory(exlude_titles, total_stats, total_books_time) function ReaderStatistics:getOldStatisticsFromDirectory(exlude_titles, total_stats)
if lfs.attributes(statistics_dir, "mode") ~= "directory" then if lfs.attributes(statistics_dir, "mode") ~= "directory" then
return return 0
end end
local total_books_time = 0
for curr_file in lfs.dir(statistics_dir) do for curr_file in lfs.dir(statistics_dir) do
local path = statistics_dir .. curr_file local path = statistics_dir .. curr_file
if lfs.attributes(path, "mode") == "file" then if lfs.attributes(path, "mode") == "file" then
local book_result = self:importFromFile(statistics_dir, curr_file) local book_result = self:importFromFile(statistics_dir, curr_file)
if book_result and book_result.title ~= self.data.title and not exlude_titles[book_result.title] then if book_result and book_result.title ~= self.data.title and not exlude_titles[book_result.title] then
table.insert(total_stats, { table.insert(total_stats, {
text = book_result.title, book_result.title,
mandatory = util.secondsToClock(book_result.total_time, false), util.secondsToClock(book_result.total_time, false),
callback = function() callback = function()
self.total_status:swithItemTable(nil, self:getDatesForBookOldFormat(book_result)) UIManager:show(KeyValuePage:new{
UIManager:show(self.total_menu) title = book_result.title,
return true kv_pairs = getDatesForBookOldFormat(book_result),
})
end, end,
}) })
total_books_time = total_books_time + tonumber(book_result.total_time) total_books_time = total_books_time + tonumber(book_result.total_time)
end end
end end
end end
end return total_books_time
function ReaderStatistics:getBookProperties()
local props = self.view.document:getProps()
if props.title == "No document" or props.title == "" then --sometime crengine returns "No document" try to get one more time
props = self.view.document:getProps()
end
return props
end end
function ReaderStatistics:onPageUpdate(pageno) function ReaderStatistics:onPageUpdate(pageno)
@ -411,14 +358,6 @@ function ReaderStatistics:onPageUpdate(pageno)
end end
end end
function ReaderStatistics:savePropertiesInToData(item)
self.data.title = item.title
self.data.authors = item.authors
self.data.language = item.language
self.data.series = item.series
end
-- For backward compatibility -- For backward compatibility
function ReaderStatistics:inplaceMigration() function ReaderStatistics:inplaceMigration()
local oldData = self:importFromFile(statistics_dir, self.data.title .. ".stat") local oldData = self:importFromFile(statistics_dir, self.data.title .. ".stat")
@ -431,12 +370,12 @@ end
-- For backward compatibility -- For backward compatibility
function ReaderStatistics:importFromFile(base_path, item) function ReaderStatistics:importFromFile(base_path, item)
item = string.gsub(item, "^%s*(.-)%s*$", "%1") --trim item = string.gsub(item, "^%s*(.-)%s*$", "%1") -- trim
if lfs.attributes(base_path .. item, "mode") == "directory" then local statistic_file = joinPath(base_path, item)
if lfs.attributes(statistic_file, "mode") == "directory" then
return return
end end
local statisticFile = base_path .. item local ok, stored = pcall(dofile, statistic_file)
local ok, stored = pcall(dofile, statisticFile)
if ok then if ok then
return stored return stored
else else

@ -64,8 +64,7 @@ function TestGrid:paintTo(bb)
end end
function TestVisible:paintTo(bb) function TestVisible:paintTo(bb)
--Draw three lines at the borders to assess what the maximum visible coordinates are -- Draw three lines at the borders to assess what the maximum visible coordinates are
v_line = math.floor(bb:getWidth() / 50) v_line = math.floor(bb:getWidth() / 50)
h_line = math.floor(bb:getHeight() / 50) h_line = math.floor(bb:getHeight() / 50)
-- Paint white background for higher contrast -- Paint white background for higher contrast
@ -165,8 +164,6 @@ function Background:onQuitApplication()
UIManager:quit() UIManager:quit()
end end
----------------------------------------------------- -----------------------------------------------------
-- example widget: a clock -- example widget: a clock
----------------------------------------------------- -----------------------------------------------------
@ -185,7 +182,6 @@ function Clock:schedFunc()
self[1][1]:free() self[1][1]:free()
self[1][1] = self:getTextWidget() self[1][1] = self:getTextWidget()
UIManager:setDirty(self) UIManager:setDirty(self)
-- reschedule
-- TODO: wait until next real second shift -- TODO: wait until next real second shift
UIManager:scheduleIn(1, function() self:schedFunc() end) UIManager:scheduleIn(1, function() self:schedFunc() end)
end end
@ -250,7 +246,6 @@ M = Menu:new{
height = 600, height = 600,
} }
----------------------------------------------------- -----------------------------------------------------
-- a reader view widget -- a reader view widget
----------------------------------------------------- -----------------------------------------------------
@ -277,72 +272,62 @@ touch_menu = TouchMenu:new{
icon = "resources/icons/appbar.pokeball.png", icon = "resources/icons/appbar.pokeball.png",
{ {
text = "item1", text = "item1",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item2", text = "item2",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item3", text = "item3",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item4", text = "item4",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item5", text = "item5",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item6", text = "item6",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item7", text = "item7",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item8", text = "item8",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item9", text = "item9",
callback = function() callback = function() end,
end,
}, },
}, },
{ {
icon = "resources/icons/appbar.page.corner.bookmark.png", icon = "resources/icons/appbar.page.corner.bookmark.png",
{ {
text = "item10", text = "item10",
callback = function() callback = function() end,
end,
}, },
{ {
text = "item11", text = "item11",
callback = function() callback = function() end,
end,
}, },
}, },
{ {
icon = "resources/icons/appbar.home.png", icon = "resources/icons/appbar.home.png",
callback = function() callback = function() DEBUG("hello world!") end
DEBUG("hello world!")
end
} }
}, },
} }
-----------------------------------------------------
-- input box widget
-----------------------------------------------------
local TestInputText = InputText:new{ local TestInputText = InputText:new{
width = 400, width = 400,
enter_callback = function() print("Entered") end, enter_callback = function() print("Entered") end,
@ -353,11 +338,43 @@ local TestInputText = InputText:new{
}, },
} }
-----------------------------------------------------
-- key value page
-----------------------------------------------------
local KeyValuePage = require("ui/widget/keyvaluepage")
local kvp = KeyValuePage:new{
title = 'Statistics',
kv_pairs = {
{"1 Current period", "00:00:00"},
{"2 Time to read", "00:00:00"},
{"3 Time to read", "00:00:00"},
{"4 Time to read", "00:00:00"},
{"5 Time to read", "00:00:00"},
{"6 Time to read", "00:00:00"},
{"7 Time to read", "00:00:00"},
{"8 Time to read", "00:00:00"},
{"9 Time to read", "00:00:00"},
{"10 Time to read", "00:00:00"},
{"11 Time to read", "00:00:00"},
"----------------------------",
{"12 Time to read", "00:00:00"},
{"13 Time to read", "00:00:00"},
{"14 Time to read", "00:00:00"},
{"15 Time to read", "00:00:00"},
{"16 Time to read", "00:00:00"},
{"17 Time to read", "00:00:00"},
{"18 Time to read", "00:00:00"},
{"19 Time to read", "00:00:00"},
{"20 Time to read", "00:00:00"},
{"21 Time to read", "00:00:00"},
},
}
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- you may want to uncomment following show calls to see the changes -- you may want to uncomment following show calls to see the changes
----------------------------------------------------------------------- -----------------------------------------------------------------------
--UIManager:show(Background:new()) --UIManager:show(Background:new())
-- UIManager:show(TestGrid) --UIManager:show(TestGrid)
UIManager:show(TestVisible) UIManager:show(TestVisible)
UIManager:show(Clock:new()) UIManager:show(Clock:new())
--UIManager:show(M) --UIManager:show(M)
@ -365,7 +382,9 @@ UIManager:show(Clock:new())
--UIManager:show(readerwindow) --UIManager:show(readerwindow)
--UIManager:show(touch_menu) --UIManager:show(touch_menu)
--UIManager:show(keyboard) --UIManager:show(keyboard)
UIManager:show(TestInputText) --UIManager:show(TestInputText)
TestInputText:onShowKeyboard() --TestInputText:onShowKeyboard()
UIManager:show(kvp)
UIManager:run() UIManager:run()

Loading…
Cancel
Save