From 11ee8d6fcc25b9a11d68cd2746a0d88da3c1184e Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 14 Feb 2016 13:47:36 -0800 Subject: [PATCH] refactor: use new KeyValuePage widget for displaying statistics --- .travis.yml | 2 +- datastorage.lua | 4 + .../apps/filemanager/filemanagerhistory.lua | 7 +- .../apps/reader/modules/readercropping.lua | 1 - frontend/apps/reader/modules/readerdogear.lua | 1 - frontend/apps/reader/modules/readerfont.lua | 1 - frontend/apps/reader/modules/readerfooter.lua | 3 +- .../apps/reader/modules/readerhyphenation.lua | 48 +-- frontend/apps/reader/modules/readerlink.lua | 1 - frontend/apps/reader/modules/readerpaging.lua | 12 +- .../apps/reader/modules/readerpanning.lua | 3 +- .../apps/reader/modules/readerrolling.lua | 12 +- frontend/device/gesturedetector.lua | 6 + frontend/docsettings.lua | 4 +- frontend/document/pdfdocument.lua | 5 +- frontend/document/picdocument.lua | 1 + frontend/ui/gesturerange.lua | 6 +- frontend/ui/rendertext.lua | 6 +- frontend/ui/widget/button.lua | 1 - frontend/ui/widget/closebutton.lua | 20 +- .../ui/widget/container/widgetcontainer.lua | 14 +- frontend/ui/widget/dictquicklookup.lua | 4 +- frontend/ui/widget/horizontalgroup.lua | 2 + frontend/ui/widget/keyvaluepage.lua | 273 +++++++++++++++ frontend/ui/widget/linewidget.lua | 12 +- frontend/ui/widget/menu.lua | 100 ++---- frontend/ui/widget/overlapgroup.lua | 18 +- frontend/ui/widget/textwidget.lua | 22 +- frontend/ui/widget/touchmenu.lua | 11 +- plugins/statistics.koplugin/main.lua | 321 +++++++----------- utils/wbuilder.lua | 87 +++-- 31 files changed, 605 insertions(+), 403 deletions(-) create mode 100644 frontend/ui/widget/keyvaluepage.lua diff --git a/.travis.yml b/.travis.yml index 12740b491..07f148612 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ script: - make all - travis_retry make testfront - 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: - make coverage diff --git a/datastorage.lua b/datastorage.lua index 22f468370..c6959fd24 100644 --- a/datastorage.lua +++ b/datastorage.lua @@ -22,6 +22,10 @@ function DataStorage:getDataDir() return data_dir end +function DataStorage:getHistoryDir() + return self:getDataDir() .. "/history" +end + local function initDataDir() local data_dir = DataStorage:getDataDir() local sub_data_dirs = {"cache", "clipboard", "data", "history", "ota", "screenshots"} diff --git a/frontend/apps/filemanager/filemanagerhistory.lua b/frontend/apps/filemanager/filemanagerhistory.lua index 1d1f0d416..7ff646cf5 100644 --- a/frontend/apps/filemanager/filemanagerhistory.lua +++ b/frontend/apps/filemanager/filemanagerhistory.lua @@ -6,10 +6,11 @@ local DataStorage = require("datastorage") local UIManager = require("ui/uimanager") local DocSettings = require("docsettings") local Menu = require("ui/widget/menu") +local joinPath = require("ffi/util").joinPath local Screen = require("device").screen local _ = require("gettext") -local history_dir = DataStorage:getDataDir() .. "/history/" +local history_dir = DataStorage:getHistoryDir() local FileManagerHistory = InputContainer:extend{ hist_menu_title = _("History"), @@ -30,7 +31,7 @@ function FileManagerHistory:onMenuHold(item) { text = _("Remove this item from history"), callback = function() - os.remove(history_dir..item.histfile) + os.remove(joinPath(history_dir, item.histfile)) self._manager:updateItemTable() UIManager:close(self.histfile_dialog) end, @@ -82,7 +83,7 @@ function FileManagerHistory:updateItemTable() self.hist = {} 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 local name = DocSettings:getNameFromHistory(f) table.insert(self.hist, { diff --git a/frontend/apps/reader/modules/readercropping.lua b/frontend/apps/reader/modules/readercropping.lua index 5c87932cb..32f5648b2 100644 --- a/frontend/apps/reader/modules/readercropping.lua +++ b/frontend/apps/reader/modules/readercropping.lua @@ -12,7 +12,6 @@ local BBoxWidget = require("ui/widget/bboxwidget") local HorizontalSpan = require("ui/widget/horizontalspan") local Button = require("ui/widget/button") local Math = require("optmath") -local DEBUG = require("dbg") local Blitbuffer = require("ffi/blitbuffer") local PageCropDialog = VerticalGroup:new{ diff --git a/frontend/apps/reader/modules/readerdogear.lua b/frontend/apps/reader/modules/readerdogear.lua index a0bded8fc..1b737fd67 100644 --- a/frontend/apps/reader/modules/readerdogear.lua +++ b/frontend/apps/reader/modules/readerdogear.lua @@ -2,7 +2,6 @@ local InputContainer = require("ui/widget/container/inputcontainer") local RightContainer = require("ui/widget/container/rightcontainer") local ImageWidget = require("ui/widget/imagewidget") local GestureRange = require("ui/gesturerange") -local UIManager = require("ui/uimanager") local Device = require("device") local Geom = require("ui/geometry") local Screen = require("device").screen diff --git a/frontend/apps/reader/modules/readerfont.lua b/frontend/apps/reader/modules/readerfont.lua index 17cd0ae56..36aa85300 100644 --- a/frontend/apps/reader/modules/readerfont.lua +++ b/frontend/apps/reader/modules/readerfont.lua @@ -8,7 +8,6 @@ local Screen = require("device").screen local Input = require("device").input local Event = require("ui/event") local UIManager = require("ui/uimanager") -local DEBUG = require("dbg") local T = require("ffi/util").template local _ = require("gettext") diff --git a/frontend/apps/reader/modules/readerfooter.lua b/frontend/apps/reader/modules/readerfooter.lua index 4c6614a7c..5fb328b07 100644 --- a/frontend/apps/reader/modules/readerfooter.lua +++ b/frontend/apps/reader/modules/readerfooter.lua @@ -14,7 +14,6 @@ local Screen = require("device").screen local Geom = require("ui/geometry") local Event = require("ui/event") local Font = require("ui/font") -local DEBUG = require("dbg") local _ = require("gettext") local util = require("util") @@ -54,7 +53,7 @@ function ReaderFooter:init() book_time_to_read = true, chapter_time_to_read = true, } - local text_default = "" + local text_default if self.settings.all_at_once then local info = {} if self.settings.battery then diff --git a/frontend/apps/reader/modules/readerhyphenation.lua b/frontend/apps/reader/modules/readerhyphenation.lua index 59da2c249..0920fe2db 100644 --- a/frontend/apps/reader/modules/readerhyphenation.lua +++ b/frontend/apps/reader/modules/readerhyphenation.lua @@ -1,5 +1,6 @@ local InputContainer = require("ui/widget/container/inputcontainer") local UIManager = require("ui/uimanager") +local JSON = require("json") local InfoMessage = require("ui/widget/infomessage") local T = require("ffi/util").template local _ = require("gettext") @@ -11,32 +12,35 @@ local ReaderHyphenation = InputContainer:new{ } 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.hyph_table = {} 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 - if v.aliases then - for i,alias in ipairs(v.aliases) do - self.lang_table[alias] = v.filename + local lang_data_file = assert(io.open("./data/hyph/languages.json"), "r") + local ok, lang_data = pcall(JSON.decode, lang_data_file:read("*all")) + + 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 diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index f8145ed00..0888f4b99 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -6,7 +6,6 @@ local Geom = require("ui/geometry") local Screen = require("device").screen local Device = require("device") local Event = require("ui/event") -local DEBUG = require("dbg") local _ = require("gettext") local ReaderLink = InputContainer:new{ diff --git a/frontend/apps/reader/modules/readerpaging.lua b/frontend/apps/reader/modules/readerpaging.lua index d64f21390..860d26c93 100644 --- a/frontend/apps/reader/modules/readerpaging.lua +++ b/frontend/apps/reader/modules/readerpaging.lua @@ -318,17 +318,9 @@ function ReaderPaging:onSwipe(arg, ges) elseif self.page_flipping_mode and self.original_page then self:gotoPage(self.original_page) elseif ges.direction == "west" then - if DCHANGE_WEST_SWIPE_TO_EAST then - self:onPagingRel(-1) - else - self:onPagingRel(1) - end + self:onPagingRel(1) elseif ges.direction == "east" then - if DCHANGE_EAST_SWIPE_TO_WEST then - self:onPagingRel(1) - else - self:onPagingRel(-1) - end + self:onPagingRel(-1) else -- trigger full refresh UIManager:setDirty(nil, "full") diff --git a/frontend/apps/reader/modules/readerpanning.lua b/frontend/apps/reader/modules/readerpanning.lua index ace5b2981..a1e362c03 100644 --- a/frontend/apps/reader/modules/readerpanning.lua +++ b/frontend/apps/reader/modules/readerpanning.lua @@ -14,8 +14,7 @@ local ReaderPanning = InputContainer:new{ } function ReaderPanning:init() - if Device:isTouchDevice() then - else + if Device:hasKeyboard() then self.key_events = { -- these will all generate the same event, just with different arguments MoveUp = { diff --git a/frontend/apps/reader/modules/readerrolling.lua b/frontend/apps/reader/modules/readerrolling.lua index 8b7afac39..1500038bb 100644 --- a/frontend/apps/reader/modules/readerrolling.lua +++ b/frontend/apps/reader/modules/readerrolling.lua @@ -261,17 +261,9 @@ end function ReaderRolling:onSwipe(arg, ges) if ges.direction == "west" or ges.direction == "north" then - if DCHANGE_WEST_SWIPE_TO_EAST then - self:onGotoViewRel(-1) - else - self:onGotoViewRel(1) - end + self:onGotoViewRel(1) elseif ges.direction == "east" or ges.direction == "south" then - if DCHANGE_EAST_SWIPE_TO_WEST then - self:onGotoViewRel(1) - else - self:onGotoViewRel(-1) - end + self:onGotoViewRel(-1) end end diff --git a/frontend/device/gesturedetector.lua b/frontend/device/gesturedetector.lua index 5f6784e90..59e1404fb 100644 --- a/frontend/device/gesturedetector.lua +++ b/frontend/device/gesturedetector.lua @@ -424,6 +424,12 @@ function GestureDetector:handleSwipe(tev) y = self.first_tevs[slot].y, 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) self:clearState(slot) return { diff --git a/frontend/docsettings.lua b/frontend/docsettings.lua index 60461ac2f..2537857e3 100644 --- a/frontend/docsettings.lua +++ b/frontend/docsettings.lua @@ -4,14 +4,14 @@ local dump = require("dump") local DocSettings = {} -local history_dir = DataStorage:getDataDir() .. "/history/" +local history_dir = DataStorage:getHistoryDir() function DocSettings:getSidecarDir(doc_path) return doc_path:match("(.*)%.")..".sdr" end function DocSettings:getHistoryPath(fullpath) - return history_dir .. "[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua" + return history_dir .. "/[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua" end function DocSettings:getPathFromHistory(hist_name) diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 4244992bc..7fe9d1008 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -31,9 +31,10 @@ function PdfDocument:init() else self:_readMetadata() 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") - end + -- end end function PdfDocument:unlock(password) diff --git a/frontend/document/picdocument.lua b/frontend/document/picdocument.lua index e298e5ff0..f244b1e14 100644 --- a/frontend/document/picdocument.lua +++ b/frontend/document/picdocument.lua @@ -10,6 +10,7 @@ local PicDocument = Document:new{ function PicDocument:init() if not pic then pic = require("ffi/pic") end + local ok ok, self._document = pcall(pic.openDocument, self.file) if not ok then error("Failed to open jpeg image") diff --git a/frontend/ui/gesturerange.lua b/frontend/ui/gesturerange.lua index 5e2085d03..fb5b7f4d4 100644 --- a/frontend/ui/gesturerange.lua +++ b/frontend/ui/gesturerange.lua @@ -11,8 +11,8 @@ local GestureRange = { scale = nil, } -function GestureRange:new(o) - local o = o or {} +function GestureRange:new(from_o) + local o = from_o or {} setmetatable(o, self) self.__index = self return o @@ -29,7 +29,7 @@ function GestureRange:match(gs) -- e.g. range = function() return self.dimen end -- for inputcontainer given that the x and y field of `self.dimen` is only -- filled when the inputcontainer is painted into blitbuffer - local range = nil + local range if type(self.range) == "function" then range = self.range() else diff --git a/frontend/ui/rendertext.lua b/frontend/ui/rendertext.lua index 23fbd3b02..fead79cf4 100644 --- a/frontend/ui/rendertext.lua +++ b/frontend/ui/rendertext.lua @@ -18,7 +18,7 @@ local GlyphCache = Cache:new{ } -- iterator over UTF8 encoded characters in a string -local function utf8Chars(input) +local function utf8Chars(input_text) local function read_next_glyph(input, pos) if string.len(input) < pos then return nil end 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) end end - return read_next_glyph, input, 1 + return read_next_glyph, input_text, 1 end function RenderText:getGlyph(face, charcode, bold) @@ -81,7 +81,7 @@ function RenderText:getGlyph(face, charcode, bold) rendered_glyph = fb_face.ftface:renderGlyph(charcode, bold) --DEBUG("fallback to font", font) break - end + end end end end diff --git a/frontend/ui/widget/button.lua b/frontend/ui/widget/button.lua index 508d3b24d..9c106b8f7 100644 --- a/frontend/ui/widget/button.lua +++ b/frontend/ui/widget/button.lua @@ -9,7 +9,6 @@ local UIManager = require("ui/uimanager") local Geom = require("ui/geometry") local Device = require("device") local Font = require("ui/font") -local DEBUG = require("dbg") local _ = require("gettext") --[[ diff --git a/frontend/ui/widget/closebutton.lua b/frontend/ui/widget/closebutton.lua index f51a8e724..89b235850 100644 --- a/frontend/ui/widget/closebutton.lua +++ b/frontend/ui/widget/closebutton.lua @@ -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 FrameContainer = require("ui/widget/container/framecontainer") local TextWidget = require("ui/widget/textwidget") local GestureRange = require("ui/gesturerange") local Font = require("ui/font") ---[[ -a button widget that shows an "×" and handles closing window when tapped ---]] local CloseButton = InputContainer:new{ - align = "right", + overlap_align = "right", window = nil, } @@ -23,7 +33,7 @@ function CloseButton:init() text_widget } - self.dimen = text_widget:getSize():copy() + self.dimen = text_widget:getSize() self.ges_events.Close = { GestureRange:new{ diff --git a/frontend/ui/widget/container/widgetcontainer.lua b/frontend/ui/widget/container/widgetcontainer.lua index dd63ec34b..e99132176 100644 --- a/frontend/ui/widget/container/widgetcontainer.lua +++ b/frontend/ui/widget/container/widgetcontainer.lua @@ -8,11 +8,15 @@ local WidgetContainer = Widget:new() function WidgetContainer:init() if self.dimen then - if not self.dimen.w then - self.dimen.w = self[1].getSize().w - end - if not self.dimen.h then - self.dimen.h = self[1].getSize().h + if self.initDimen then + self:initDimen() + else + if not self.dimen.w then + 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 diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 76e262721..242ad32f1 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -91,9 +91,7 @@ function DictQuickLookup:init() }, } table.insert(self.dict_bar, - CloseButton:new{ - window = self, - }) + CloseButton:new{ window = self, }) end end diff --git a/frontend/ui/widget/horizontalgroup.lua b/frontend/ui/widget/horizontalgroup.lua index 66d80f910..7383d10db 100644 --- a/frontend/ui/widget/horizontalgroup.lua +++ b/frontend/ui/widget/horizontalgroup.lua @@ -39,6 +39,8 @@ function HorizontalGroup:paintTo(bb, x, y) widget:paintTo(bb, x + self._offsets[i].x, y) elseif self.align == "bottom" then 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 diff --git a/frontend/ui/widget/keyvaluepage.lua b/frontend/ui/widget/keyvaluepage.lua new file mode 100644 index 000000000..9ad9a9d2b --- /dev/null +++ b/frontend/ui/widget/keyvaluepage.lua @@ -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 diff --git a/frontend/ui/widget/linewidget.lua b/frontend/ui/widget/linewidget.lua index 19b2a2e3e..be2fa08e3 100644 --- a/frontend/ui/widget/linewidget.lua +++ b/frontend/ui/widget/linewidget.lua @@ -19,13 +19,13 @@ function LineWidget:paintTo(bb, x, y) else if self.empty_segments then bb:paintRect(x, y, - self.empty_segments[1].s, - self.dimen.h, - self.background) + self.empty_segments[1].s, + self.dimen.h, + self.background) bb:paintRect(x + self.empty_segments[1].e, y, - self.dimen.w - x - self.empty_segments[1].e, - self.dimen.h, - self.background) + self.dimen.w - x - self.empty_segments[1].e, + self.dimen.h, + self.background) else bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.background) end diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index dcc8db3f5..98b64a632 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -8,7 +8,6 @@ local BottomContainer = require("ui/widget/container/bottomcontainer") local UnderlineContainer = require("ui/widget/container/underlinecontainer") local FocusManager = require("ui/widget/focusmanager") local TextWidget = require("ui/widget/textwidget") -local LineWidget = require("ui/widget/linewidget") local OverlapGroup = require("ui/widget/overlapgroup") local VerticalSpan = require("ui/widget/verticalspan") local HorizontalSpan = require("ui/widget/horizontalspan") @@ -82,7 +81,7 @@ NOTICE: @menu entry must be provided in order to close the menu --]] local MenuCloseButton = InputContainer:new{ - align = "right", + overlap_align = "right", menu = nil, dimen = Geom:new{}, } @@ -94,7 +93,10 @@ function MenuCloseButton:init() } 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 = { GestureRange:new{ @@ -110,45 +112,6 @@ function MenuCloseButton:onClose() return true 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 --]] @@ -430,7 +393,7 @@ function Menu:init() -- start to set up widget layout -- ----------------------------------- self.menu_title = TextWidget:new{ - align = "center", + overlap_align = "center", text = self.title, face = self.tface, } @@ -578,9 +541,7 @@ function Menu:init() if Device:isTouchDevice() then if self.has_close_button then table.insert(self.title_bar, - MenuCloseButton:new{ - menu = self, - }) + MenuCloseButton:new{ menu = self }) end -- watch for outer region if it's a self contained widget if self.is_popout then @@ -681,27 +642,20 @@ function Menu:updateItems(select_number) item_shortcut = "Ent" end end - local item_tmp - if self.item_table[i].text == "-" then - item_tmp = SeparatorMenuItem:new{ - dimen = self.item_dimen:new{ h = Screen:scaleBySize(10) }, - } - else - item_tmp = MenuItem:new{ - show_parent = self.show_parent, - state = self.item_table[i].state, - state_size = self.state_size or {}, - text = self.item_table[i].text, - mandatory = self.item_table[i].mandatory, - bold = self.item_table.current == i, - face = self.cface, - dimen = self.item_dimen:new(), - shortcut = item_shortcut, - shortcut_style = shortcut_style, - table = self.item_table[i], - menu = self, - } - end + local item_tmp = MenuItem:new{ + show_parent = self.show_parent, + state = self.item_table[i].state, + state_size = self.state_size or {}, + text = self.item_table[i].text, + mandatory = self.item_table[i].mandatory, + bold = self.item_table.current == i, + face = self.cface, + dimen = self.item_dimen:new(), + shortcut = item_shortcut, + shortcut_style = shortcut_style, + table = self.item_table[i], + menu = self, + } table.insert(self.item_group, item_tmp) -- this is for focus manager table.insert(self.layout, {item_tmp}) @@ -923,17 +877,9 @@ end function Menu:onSwipe(arg, ges_ev) if ges_ev.direction == "west" then - if DCHANGE_WEST_SWIPE_TO_EAST then - self:onPrevPage() - else - self:onNextPage() - end + self:onNextPage() elseif ges_ev.direction == "east" then - if DCHANGE_WEST_SWIPE_TO_EAST then - self:onNextPage() - else - self:onPrevPage() - end + self:onPrevPage() end end diff --git a/frontend/ui/widget/overlapgroup.lua b/frontend/ui/widget/overlapgroup.lua index e8b2e1f42..bd35362fe 100644 --- a/frontend/ui/widget/overlapgroup.lua +++ b/frontend/ui/widget/overlapgroup.lua @@ -22,14 +22,22 @@ function OverlapGroup:getSize() 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 self._size.w = self.dimen.w + else + self.dimen.w = self._size.w end if self.dimen.h then self._size.h = self.dimen.h + else + self.dimen.h = self._size.h end - - return self._size end function OverlapGroup:paintTo(bb, x, y) @@ -37,10 +45,12 @@ function OverlapGroup:paintTo(bb, x, y) for i, wget in ipairs(self) do 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) - elseif wget.align == "center" then + elseif wget.overlap_align == "center" then 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 -- default to left wget:paintTo(bb, x, y) diff --git a/frontend/ui/widget/textwidget.lua b/frontend/ui/widget/textwidget.lua index 3c0972408..d06b4bbde 100644 --- a/frontend/ui/widget/textwidget.lua +++ b/frontend/ui/widget/textwidget.lua @@ -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) --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() --if not self._bb then --self:_render() --end --return { w = self._length, h = self._bb:getHeight() } - local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold) - if not tsize then - return Geom:new{} - end - self._length = tsize.x - self._height = self.face.size * 1.5 + self:updateSize() return Geom:new{ w = self._length, h = self._height, } end +function TextWidget:setText(text) + self.text = text + self:updateSize() +end + function TextWidget:paintTo(bb, x, y) --if not self._bb then --self:_render() diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index a95f5a096..85dec16fa 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -94,16 +94,13 @@ function TouchMenuItem:onTapSelect(arg, ges) end if enabled == false then return end - UIManager:scheduleIn(0.0, function() - self.item_frame.invert = true - UIManager:setDirty(self.show_parent, function() - return "ui", self.dimen - end) + self.item_frame.invert = true + UIManager:setDirty(self.show_parent, function() + return "ui", self.dimen end) + -- yield to main UI loop to invert item UIManager:scheduleIn(0.1, function() self.menu:onMenuSelect(self.item) - end) - UIManager:scheduleIn(0.5, function() self.item_frame.invert = false UIManager:setDirty(self.show_parent, function() return "ui", self.dimen diff --git a/plugins/statistics.koplugin/main.lua b/plugins/statistics.koplugin/main.lua index b17d69db9..16a609de4 100755 --- a/plugins/statistics.koplugin/main.lua +++ b/plugins/statistics.koplugin/main.lua @@ -1,21 +1,22 @@ local InputContainer = require("ui/widget/container/inputcontainer") local MultiInputDialog = require("ui/widget/multiinputdialog") local CenterContainer = require("ui/widget/container/centercontainer") +local KeyValuePage = require("ui/widget/keyvaluepage") local UIManager = require("ui/uimanager") local Screen = require("device").screen -local Menu = require("ui/widget/menu") local Font = require("ui/font") local TimeVal = require("ui/timeval") local DataStorage = require("datastorage") local lfs = require("libs/libkoreader-lfs") local DEBUG = require("dbg") local T = require("ffi/util").template +local joinPath = require("ffi/util").joinPath local _ = require("gettext") local util = require("util") local tableutil = require("tableutil") local statistics_dir = DataStorage:getDataDir() .. "/statistics/" -local history_dir = DataStorage:getDataDir() .. "/history/" +local history_dir = DataStorage:getHistoryDir() local ReaderStatistics = InputContainer:new { last_time = nil, @@ -51,37 +52,37 @@ function ReaderStatistics:init() self.last_time = TimeVal:now() 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) - --first execution + -- first execution if self.is_enabled then - local book_properties = self:getBookProperties() - self:savePropertiesInToData(book_properties) if not self.data then - --first time merge data - self:inplaceMigration(); + self.data = { performance_in_pages= {} } + self:inplaceMigration(); -- first time merge data 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() return end end -function ReaderStatistics:addToMainMenu(tab_item_table) - table.insert(tab_item_table.plugins, { - text = _("Statistics"), - sub_item_table = { - self:getStatisticEnabledMenuTable(), - self:getStatisticSettingsMenuTable(), - self:getStatisticForCurrentBookMenuTable(), - self:getStatisticTotalStatisticMenuTable(), - } - }) -end - -function ReaderStatistics:getStatisticEnabledMenuTable() +function ReaderStatistics:getStatisticEnabledMenuItem() return { - text_func = function() - return _("Enabled") - end, + text = _("Enabled"), checked_func = function() return self.is_enabled end, callback = function() -- if was enabled, have to save data to file @@ -99,18 +100,6 @@ function ReaderStatistics:getStatisticEnabledMenuTable() } 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() self.settings_dialog = MultiInputDialog:new { title = _("Statistics settings"), @@ -138,9 +127,9 @@ function ReaderStatistics:updateSettings() { text = _("Apply"), callback = function() + self:saveSettings(MultiInputDialog:getFields()) self.settings_dialog:onClose() UIManager:close(self.settings_dialog) - self:saveSettings(MultiInputDialog:getFields()) end }, }, @@ -153,101 +142,74 @@ function ReaderStatistics:updateSettings() UIManager:show(self.settings_dialog) end -function ReaderStatistics:getStatisticForCurrentBookMenuTable() - self.status_menu = {} - - local book_status = Menu:new { - title = _("Status"), - item_table = self:updateCurrentStat(), - is_borderless = true, - is_popout = false, - is_enable_shortcut = false, - width = Screen:getWidth(), - height = Screen:getHeight(), - cface = Font:getFace("cfont", 20), - } - - self.status_menu = CenterContainer:new { - dimen = Screen:getSize(), - book_status, - } - - book_status.close_callback = function() - UIManager:close(self.status_menu) - end - - book_status.show_parent = self.status_menu - - return { - text = _("Current"), - 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 - } +function ReaderStatistics:addToMainMenu(tab_item_table) + table.insert(tab_item_table.plugins, { + text = _("Statistics"), + sub_item_table = { + self:getStatisticEnabledMenuItem(), + { + text = _("Settings"), + callback = function() self:updateSettings() end, + }, + { + text = _("Current book"), + callback = function() + UIManager:show(KeyValuePage:new{ + title = _("Statistics"), + kv_pairs = self:getCurrentStat(), + }) + end + }, + { + text = _("All books"), + callback = function() + total_msg, kv_pairs = self:getTotalStat() + UIManager:show(KeyValuePage:new{ + title = total_msg, + kv_pairs = kv_pairs, + }) + end + }, + }, + }) end -function ReaderStatistics:getStatisticTotalStatisticMenuTable() - 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) +function ReaderStatistics:getCurrentStat() + local dates = {} + for k, v in pairs(self.data.performance_in_pages) do + dates[os.date("%Y-%m-%d", k)] = "" 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 { - text = _("Total"), - callback = function() - self.total_status:swithItemTable(nil, self:updateTotalStat()) - UIManager:show(self.total_menu) - return true - end + { _("Current period"), util.secondsToClock(self.current_period, false) }, + { _("Time to read"), util.secondsToClock((self.data.pages - current_page) * avg_time_per_page, false) }, + { _("Total time"), util.secondsToClock(self.data.total_time_in_sec, false) }, + { _("Total highlights"), self.data.highlights }, + { _("Total notes"), self.data.notes }, + { _("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 -function ReaderStatistics:updateCurrentStat() - local stats = {} - local dates = {} - - for k, v in pairs(self.data.performance_in_pages) do - dates[os.date("%Y-%m-%d", k)] = "" +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 - - 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 + return result end -- For backward compatibility -function ReaderStatistics:getDatesForBookOldFormat(book) +function getDatesForBookOldFormat(book) local dates = {} for k, v in pairs(book.details) do @@ -267,11 +229,10 @@ function ReaderStatistics:getDatesForBookOldFormat(book) end end - return self:generateReadBooksTable(book.title, dates) + return generateReadBooksTable(book.title, dates) end - -function ReaderStatistics:getDatesForBook(book) +function getDatesForBook(book) local dates = {} for k, v in pairs(book.performance_in_pages) do @@ -283,107 +244,93 @@ function ReaderStatistics:getDatesForBook(book) count = 1 } else - dates[date_text] = { - read = dates[date_text].read + v, - count = dates[date_text].count + 1, - date = dates[date_text].date - } + -- TODO: test this + local entry = dates[date_text] + entry.read = entry.read + v + entry.count = entry.count + 1 end end - return self: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 + return generateReadBooksTable(book.title, dates) 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() - 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) - + -- find stats for all other books in history + local proceded_titles, total_books_time = self:getStatisticsFromHistory(total_stats) + total_books_time = total_books_time + self:getOldStatisticsFromDirectory(proceded_titles, total_stats) 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) }) - table.insert(total_stats, 2, { text = "-" }) - table.insert(total_stats, 3, { - 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 + return T(_("Total hours read %1"), + util.secondsToClock(total_books_time, false)), + total_stats end -function ReaderStatistics:getStatisticsFromHistory(total_stats, total_books_time) +function ReaderStatistics:getStatisticsFromHistory(total_stats) local titles = {} + local total_books_time = 0 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 local book_result = self:importFromFile(history_dir, curr_file) local book_stats = book_result.stats if book_stats and book_stats.title ~= self.data.title then titles[book_stats.title] = true table.insert(total_stats, { - text = book_stats.title, - mandatory = util.secondsToClock(book_stats.total_time_in_sec, false), + book_stats.title, + util.secondsToClock(book_stats.total_time_in_sec, false), callback = function() - self.total_status:swithItemTable(nil, self:getDatesForBook(book_stats)) - UIManager:show(self.total_menu) - return true + UIManager:show(KeyValuePage:new{ + title = book_stats.title, + kv_pairs = getDatesForBook(book_stats), + }) end, }) total_books_time = total_books_time + tonumber(book_stats.total_time_in_sec) end end end - return titles + return titles, total_books_time end -- 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 - return + return 0 end + local total_books_time = 0 for curr_file in lfs.dir(statistics_dir) do local path = statistics_dir .. curr_file if lfs.attributes(path, "mode") == "file" then 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 table.insert(total_stats, { - text = book_result.title, - mandatory = util.secondsToClock(book_result.total_time, false), + book_result.title, + util.secondsToClock(book_result.total_time, false), callback = function() - self.total_status:swithItemTable(nil, self:getDatesForBookOldFormat(book_result)) - UIManager:show(self.total_menu) - return true + UIManager:show(KeyValuePage:new{ + title = book_result.title, + kv_pairs = getDatesForBookOldFormat(book_result), + }) end, }) total_books_time = total_books_time + tonumber(book_result.total_time) end end end -end - -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 + return total_books_time end function ReaderStatistics:onPageUpdate(pageno) @@ -411,14 +358,6 @@ function ReaderStatistics:onPageUpdate(pageno) 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 function ReaderStatistics:inplaceMigration() local oldData = self:importFromFile(statistics_dir, self.data.title .. ".stat") @@ -431,12 +370,12 @@ end -- For backward compatibility function ReaderStatistics:importFromFile(base_path, item) - item = string.gsub(item, "^%s*(.-)%s*$", "%1") --trim - if lfs.attributes(base_path .. item, "mode") == "directory" then + item = string.gsub(item, "^%s*(.-)%s*$", "%1") -- trim + local statistic_file = joinPath(base_path, item) + if lfs.attributes(statistic_file, "mode") == "directory" then return end - local statisticFile = base_path .. item - local ok, stored = pcall(dofile, statisticFile) + local ok, stored = pcall(dofile, statistic_file) if ok then return stored else diff --git a/utils/wbuilder.lua b/utils/wbuilder.lua index 0524b29e5..421725e24 100755 --- a/utils/wbuilder.lua +++ b/utils/wbuilder.lua @@ -64,8 +64,7 @@ function TestGrid:paintTo(bb) end 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) h_line = math.floor(bb:getHeight() / 50) -- Paint white background for higher contrast @@ -165,8 +164,6 @@ function Background:onQuitApplication() UIManager:quit() end - - ----------------------------------------------------- -- example widget: a clock ----------------------------------------------------- @@ -185,7 +182,6 @@ function Clock:schedFunc() self[1][1]:free() self[1][1] = self:getTextWidget() UIManager:setDirty(self) - -- reschedule -- TODO: wait until next real second shift UIManager:scheduleIn(1, function() self:schedFunc() end) end @@ -250,7 +246,6 @@ M = Menu:new{ height = 600, } - ----------------------------------------------------- -- a reader view widget ----------------------------------------------------- @@ -277,72 +272,62 @@ touch_menu = TouchMenu:new{ icon = "resources/icons/appbar.pokeball.png", { text = "item1", - callback = function() - end, + callback = function() end, }, { text = "item2", - callback = function() - end, + callback = function() end, }, { text = "item3", - callback = function() - end, + callback = function() end, }, { text = "item4", - callback = function() - end, + callback = function() end, }, { text = "item5", - callback = function() - end, + callback = function() end, }, { text = "item6", - callback = function() - end, + callback = function() end, }, { text = "item7", - callback = function() - end, + callback = function() end, }, { text = "item8", - callback = function() - end, + callback = function() end, }, { text = "item9", - callback = function() - end, + callback = function() end, }, }, { icon = "resources/icons/appbar.page.corner.bookmark.png", { text = "item10", - callback = function() - end, + callback = function() end, }, { text = "item11", - callback = function() - end, + callback = function() end, }, }, { icon = "resources/icons/appbar.home.png", - callback = function() - DEBUG("hello world!") - end + callback = function() DEBUG("hello world!") end } }, } +----------------------------------------------------- +-- input box widget +----------------------------------------------------- local TestInputText = InputText:new{ width = 400, 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 ----------------------------------------------------------------------- --UIManager:show(Background:new()) --- UIManager:show(TestGrid) +--UIManager:show(TestGrid) UIManager:show(TestVisible) UIManager:show(Clock:new()) --UIManager:show(M) @@ -365,7 +382,9 @@ UIManager:show(Clock:new()) --UIManager:show(readerwindow) --UIManager:show(touch_menu) --UIManager:show(keyboard) -UIManager:show(TestInputText) -TestInputText:onShowKeyboard() +--UIManager:show(TestInputText) +--TestInputText:onShowKeyboard() + +UIManager:show(kvp) UIManager:run()