mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
refactor: use new KeyValuePage widget for displaying statistics
This commit is contained in:
@@ -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
|
||||||
|
|||||||
273
frontend/ui/widget/keyvaluepage.lua
Normal file
273
frontend/ui/widget/keyvaluepage.lua
Normal file
@@ -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 {
|
|
||||||
title = _("Total"),
|
|
||||||
item_table = self:updateTotalStat(),
|
|
||||||
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
|
|
||||||
|
|
||||||
self.total_status.show_parent = self.total_menu
|
|
||||||
|
|
||||||
return {
|
|
||||||
text = _("Total"),
|
|
||||||
callback = function()
|
|
||||||
self.total_status:swithItemTable(nil, self:updateTotalStat())
|
|
||||||
UIManager:show(self.total_menu)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function ReaderStatistics:updateCurrentStat()
|
|
||||||
local stats = {}
|
|
||||||
local dates = {}
|
local dates = {}
|
||||||
|
|
||||||
for k, v in pairs(self.data.performance_in_pages) do
|
for k, v in pairs(self.data.performance_in_pages) do
|
||||||
dates[os.date("%Y-%m-%d", k)] = ""
|
dates[os.date("%Y-%m-%d", k)] = ""
|
||||||
end
|
end
|
||||||
|
local total_days = util.tableSize(dates)
|
||||||
|
|
||||||
local read_pages = util.tableSize(self.data.performance_in_pages)
|
local read_pages = util.tableSize(self.data.performance_in_pages)
|
||||||
local current_page = self.view.state.page --get current page from the view
|
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
|
local avg_time_per_page = self.data.total_time_in_sec / read_pages
|
||||||
|
|
||||||
table.insert(stats, { text = _("Current period"), mandatory = util.secondsToClock(self.current_period, false) })
|
return {
|
||||||
table.insert(stats, { text = _("Time to read"), mandatory = util.secondsToClock((self.data.pages - current_page) * average_time_per_page, false) })
|
{ _("Current period"), util.secondsToClock(self.current_period, false) },
|
||||||
table.insert(stats, { text = _("Total time"), mandatory = util.secondsToClock(self.data.total_time_in_sec, false) })
|
{ _("Time to read"), util.secondsToClock((self.data.pages - current_page) * avg_time_per_page, false) },
|
||||||
table.insert(stats, { text = _("Total highlights"), mandatory = self.data.highlights })
|
{ _("Total time"), util.secondsToClock(self.data.total_time_in_sec, false) },
|
||||||
table.insert(stats, { text = _("Total notes"), mandatory = self.data.notes })
|
{ _("Total highlights"), self.data.highlights },
|
||||||
table.insert(stats, { text = _("Total days"), mandatory = util.tableSize(dates) })
|
{ _("Total notes"), self.data.notes },
|
||||||
table.insert(stats, { text = _("Average time per page"), mandatory = util.secondsToClock(average_time_per_page, false) })
|
{ _("Total days"), total_days },
|
||||||
table.insert(stats, { text = _("Read pages/Total pages"), mandatory = read_pages .. "/" .. self.data.pages })
|
{ _("Average time per page"), util.secondsToClock(avg_time_per_page, false) },
|
||||||
return stats
|
{ _("Read pages/Total pages"), read_pages .. "/" .. self.data.pages },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function generateReadBooksTable(title, dates)
|
||||||
|
local result = {}
|
||||||
|
for k, v in tableutil.spairs(dates, function(t, a, b) return t[b].date < t[a].date end) do
|
||||||
|
table.insert(result, {
|
||||||
|
k,
|
||||||
|
T(_("Pages (%1) Time: %2"), v.count, util.secondsToClock(v.read, false))
|
||||||
|
})
|
||||||
|
end
|
||||||
|
return result
|
||||||
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
|
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:generateReadBooksTable(title, dates)
|
-- find stats for all other books in history
|
||||||
local result = {}
|
local proceded_titles, total_books_time = self:getStatisticsFromHistory(total_stats)
|
||||||
table.insert(result, { text = title })
|
total_books_time = total_books_time + self:getOldStatisticsFromDirectory(proceded_titles, total_stats)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
function ReaderStatistics:updateTotalStat()
|
|
||||||
local total_stats = {}
|
|
||||||
local total_books_time = 0
|
|
||||||
|
|
||||||
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()
|
||||||
|
|||||||
Reference in New Issue
Block a user