Merge pull request #1873 from koreader/houqp-master

layout adjustment for readerstatus & autoRefreshTime bug fix
pull/1875/head
Huang Xin 8 years ago
commit 30c630ba2f

@ -18,6 +18,11 @@ function ReaderDogear:init()
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
widget,
}
self:resetLayout()
end
function ReaderDogear:resetLayout()
self[1].dimen.w = Screen:getWidth()
if Device:isTouchDevice() then
self.ges_events = {
Tap = {

@ -19,6 +19,11 @@ function ReaderFlipping:init()
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
widget,
}
self:resetLayout()
end
function ReaderFlipping:resetLayout()
self[1].dimen.w = Screen:getWidth()
if Device:isTouchDevice() then
self.ges_events = {
Tap = {

@ -85,7 +85,7 @@ function ReaderFooter:init()
text = text_default,
face = Font:getFace(self.text_font_face, self.text_font_size),
}
local text_width = self.progress_text:getSize().w
self.text_width = self.progress_text:getSize().w
local ticks_candidates = {}
if self.ui.toc and self.settings.toc_markers then
local max_level = self.ui.toc:getMaxDepth()
@ -99,40 +99,67 @@ function ReaderFooter:init()
table.sort(ticks_candidates, function(a, b) return #a > #b end)
end
self.progress_bar = ProgressWidget:new{
width = math.floor(Screen:getWidth() - text_width - self.padding),
width = nil, -- width will be updated in self:resetLayout()
height = self.bar_height,
percentage = self.progress_percentage,
ticks = ticks_candidates[1] or {},
tick_width = DMINIBAR_TOC_MARKER_WIDTH,
last = self.pages,
}
local horizontal_group = HorizontalGroup:new{}
local bar_container = RightContainer:new{
dimen = Geom:new{ w = Screen:getWidth() - text_width, h = self.height },
self.horizontal_group = HorizontalGroup:new{}
self.bar_container = RightContainer:new{
dimen = Geom:new{ w = Screen:getWidth() - self.text_width, h = self.height },
self.progress_bar,
}
local text_container = CenterContainer:new{
dimen = Geom:new{ w = text_width, h = self.height },
dimen = Geom:new{ w = self.text_width, h = self.height },
self.progress_text,
}
if self.settings.progress_bar then
table.insert(horizontal_group, bar_container)
table.insert(self.horizontal_group, self.bar_container)
end
table.insert(horizontal_group, text_container)
table.insert(self.horizontal_group, text_container)
self[1] = BottomContainer:new{
dimen = Screen:getSize(),
BottomContainer:new{
dimen = Geom:new{w = Screen:getWidth(), h = self.height*2},
FrameContainer:new{
horizontal_group,
self.horizontal_group,
background = Blitbuffer.COLOR_WHITE,
bordersize = 0,
padding = 0,
}
}
}
self.dimen = self[1]:getSize()
self:updateFooterPage()
self.mode = G_reader_settings:readSetting("reader_footer_mode") or self.mode
self:applyFooterMode()
self:resetLayout()
if self.settings.auto_refresh_time then
if not self.autoRefreshTime then
self.autoRefreshTime = function()
self:updateFooterPage()
UIManager:setDirty(self.view.dialog, "ui", self[1][1][1].dimen)
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.autoRefreshTime)
end
end
self.onCloseDocument = function()
UIManager:unschedule(self.autoRefreshTime)
end
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.autoRefreshTime)
end
end
function ReaderFooter:resetLayout()
self.progress_bar.width = math.floor(Screen:getWidth() - self.text_width - self.padding)
self.horizontal_group:resetLayout()
self.bar_container.dimen.w = Screen:getWidth() - self.text_width
self[1].dimen = Screen:getSize()
self[1][1].dimen.w = Screen:getWidth()
self.dimen = self[1]:getSize()
local range = Geom:new{
x = Screen:getWidth()*DTAP_ZONE_MINIBAR.x,
y = Screen:getHeight()*DTAP_ZONE_MINIBAR.y,
@ -155,19 +182,6 @@ function ReaderFooter:init()
},
}
end
self.mode = G_reader_settings:readSetting("reader_footer_mode") or self.mode
self:applyFooterMode()
if self.settings.auto_refresh_time then
self.autoRefreshTime = function()
self:updateFooterPage()
UIManager:setDirty(self.view.dialog, "ui", self[1][1][1].dimen)
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.autoRefreshTime)
end
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.autoRefreshTime)
self.onCloseDocument = function()
UIManager:unschedule(self.autoRefreshTime)
end
end
end
local options = {
@ -294,7 +308,7 @@ function ReaderFooter:updateFooterPage()
if self.settings.chapter_time_to_read then
table.insert(info, self:getChapterTimeToRead())
end
self.progress_text.text = table.concat(info, " | ")
self.progress_text:setText(table.concat(info, " | "))
else
local info = ""
if self.mode == 1 then
@ -312,7 +326,7 @@ function ReaderFooter:updateFooterPage()
elseif self.mode == 7 then
info = self:getChapterTimeToRead()
end
self.progress_text.text = info
self.progress_text:setText(info)
end
end

@ -1,5 +1,5 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local StatusWidget = require("ui/widget/statuswidget")
local BookStatusWidget = require("ui/widget/bookstatuswidget")
local UIManager = require("ui/uimanager")
local _ = require("gettext")
@ -20,29 +20,27 @@ function ReaderStatus:init()
if self.ui.document.is_djvu or self.ui.document.is_pic then
self.enabled = false
return
end
-- register event listener if enabled
self.onEndOfBook = function()
self:showStatus()
end
self.total_pages = self.document:getPageCount()
self.ui:registerPostInitCallback(function()
else
self.total_pages = self.document:getPageCount()
self.ui.menu:registerToMainMenu(self)
end)
-- register event listener if enabled
self.onEndOfBook = function()
self:showStatus()
end
end
end
function ReaderStatus:addToMainMenu(tab_item_table)
table.insert(tab_item_table.typeset, {
text = _("Status"),
table.insert(tab_item_table.info, {
text = _("Book status"),
callback = function()
self:showStatus()
UIManager:setDirty("all")
end,
})
end
function ReaderStatus:showStatus()
local status_page = StatusWidget:new {
local status_page = BookStatusWidget:new {
thumbnail = self.document:getCoverPageImage(),
props = self.document:getProps(),
document = self.document,

@ -113,7 +113,7 @@ end
function ReaderView:resetLayout()
for i, widget in ipairs(self) do
widget:init()
widget:resetLayout()
end
end

@ -171,12 +171,6 @@ function ReaderUI:init()
view = self.view,
ui = self
}, true)
-- history view
self:registerModule("history", FileManagerHistory:new{
dialog = self.dialog,
menu = self.menu,
ui = self,
})
-- frontlight controller
if Device:hasFrontlight() then
self:registerModule("frontlight", ReaderFrontLight:new{
@ -297,13 +291,17 @@ function ReaderUI:init()
view = self.view,
ui = self
})
-- book status
self:registerModule("status", ReaderStatus:new{
ui = self,
document = self.document,
view = self.view,
})
-- history view
self:registerModule("history", FileManagerHistory:new{
dialog = self.dialog,
ui = self,
})
-- koreader plugins
for _,plugin_module in ipairs(PluginLoader:loadPlugins()) do
DEBUG("Loaded plugin", plugin_module.name, "at", plugin_module.path)

@ -128,25 +128,25 @@ function Device:onPowerEvent(ev)
UIManager:scheduleIn(10, self.suspend)
elseif (ev == "Power" or ev == "Resume") and self.screen_saver_mode then
DEBUG("Resuming...")
local UIManager = require("ui/uimanager")
UIManager:unschedule(self.suspend)
self:resume()
Screensaver:close()
-- restore to previous rotation mode
self.screen:setRotationMode(self.orig_rotation_mode)
local UIManager = require("ui/uimanager")
UIManager:unschedule(self.suspend)
if self:needsScreenRefreshAfterResume() then
self.screen:refreshFull()
end
self.screen_saver_mode = false
self.powerd:refreshCapacity()
Screensaver:close()
self.powerd:afterResume()
end
end
-- Hardware function to suspend the device
-- Hardware specific method to suspend the device
function Device:suspend() end
-- Hardware function to resume the device
-- Hardware specific method to resume the device
function Device:resume() end
function Device:usbPlugIn()

@ -49,7 +49,7 @@ local function _serialize(what, outt, indent, max_lv, history)
elseif type(what) == "number" then
if isUbuntuTouch then
-- FIXME: the `SDL_CreateRenderer` function in Ubuntu touch somehow
-- use a strange locale that formats number like this: 1.10000000000000g+02
-- use a strange locale that formats number like this: 1.10000000000000g+02
-- which cannot be recognized by loadfile after the number is dumped.
-- Here the workaround is to preserve enough precision in "%.13e" format.
insert(outt, string.format("%.13e", what))
@ -59,7 +59,7 @@ local function _serialize(what, outt, indent, max_lv, history)
elseif type(what) == "boolean" then
insert(outt, tostring(what))
elseif type(what) == "function" then
insert(outt, "nil --[[ FUNCTION ]]")
insert(outt, tostring(what))
elseif type(what) == "nil" then
insert(outt, "nil")
end

@ -39,6 +39,7 @@ function GestureRange:match(gs)
return false
end
end
if self.rate then
-- This filed restraints the upper limit rate(matches per second).
-- It's most useful for e-ink devices with less powerfull CPUs and

@ -134,7 +134,7 @@ end
--- Measure rendered size for a given text.
--
-- Note this function does not render the text into a bitmap. Use it if you
-- only care about the size for the rendered result.
-- only need the estimated size information.
--
-- @int x start position for a given text (within maximum width)
-- @int width maximum rendering width in pixels (think of it as size of the bitmap)
@ -170,13 +170,27 @@ function RenderText:sizeUtf8Text(x, width, face, text, kerning, bold)
--- RenderText size information
-- @table RenderTextSize
-- @field x length of the text on x coordinates
-- @field y_top top offset for the text (relative to center of the text)
-- @field y_bottom bottom offset for the text (relative to center of the text)
-- @field x length of the text on x coordinate
-- @field y_top distance between top-most pixel (scanline) and baseline
-- (bearingY)
-- @field y_bottom distance between bottom-most pixel (scanline) and
-- baseline (height - y_top)
return { x = pen_x, y_top = pen_y_top, y_bottom = pen_y_bottom }
end
function RenderText:renderUtf8Text(buffer, x, y, face, text, kerning, bold, fgcolor, width)
--- Render a given text into a given BlitBuffer
--
-- @tparam BlitBuffer dest_bb Buffer to blit into
-- @int x starting x coordinate position within dest_bb
-- @int baseline y coordinate for baseline, within dest_bb
-- @tparam ui.font.FontFaceObj face font face that will be used for rendering
-- @string text text to render
-- @bool[opt=false] kerning whether the text should be measured with kerning
-- @bool[opt=false] bold whether the text should be measured as bold
-- @tparam[opt=BlitBuffer.COLOR_BLACK] BlitBuffer.COLOR fgcolor foreground color
-- @int[opt=nil] width maximum rendering width
-- @return int width of rendered bitmap
function RenderText:renderUtf8Text(dest_bb, x, baseline, face, text, kerning, bold, fgcolor, width)
if not text then
DEBUG("renderUtf8Text called without text");
return 0
@ -190,7 +204,7 @@ function RenderText:renderUtf8Text(buffer, x, y, face, text, kerning, bold, fgco
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
local pen_x = 0
local prevcharcode = 0
local text_width = buffer:getWidth() - x
local text_width = dest_bb:getWidth() - x
if width and width < text_width then
text_width = width
end
@ -200,9 +214,10 @@ function RenderText:renderUtf8Text(buffer, x, y, face, text, kerning, bold, fgco
if kerning and (prevcharcode ~= 0) then
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
end
buffer:colorblitFrom(
dest_bb:colorblitFrom(
glyph.bb,
x + pen_x + glyph.l, y - glyph.t,
x + pen_x + glyph.l,
baseline - glyph.t,
0, 0,
glyph.bb:getWidth(), glyph.bb:getHeight(),
fgcolor)

@ -227,9 +227,7 @@ end
-- UIManager:unschedule(self.anonymousFunction)
function UIManager:unschedule(action)
for i = #self._task_queue, 1, -1 do
local task = self._task_queue[i]
if task.action == action then
-- remove from table
if self._task_queue[i].action == action then
table.remove(self._task_queue, i)
end
end

@ -3,6 +3,7 @@ local FrameContainer = require("ui/widget/container/framecontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local OverlapGroup = require("ui/widget/overlapgroup")
local VerticalGroup = require("ui/widget/verticalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local VerticalSpan = require("ui/widget/verticalspan")
@ -24,7 +25,6 @@ local Blitbuffer = require("ffi/blitbuffer")
local Screen = require("device").screen
local Font = require("ui/font")
local TimeVal = require("ui/timeval")
local RenderText = require("ui/rendertext")
local template = require("ffi/util").template
local util = require("util")
@ -38,7 +38,8 @@ local _ = require("gettext")
["status"] = "Reading"
["modified"] = "24.01.2016"
},]]
local StatusWidget = InputContainer:new{
local BookStatusWidget = InputContainer:new{
padding = Screen:scaleBySize(15),
settings = nil,
thumbnail = nil,
props = nil,
@ -56,7 +57,7 @@ local StatusWidget = InputContainer:new{
}
}
function StatusWidget:init()
function BookStatusWidget:init()
self.stats.pages = self.document:getPageCount()
self:getStatisticsSettings()
if self.settings then
@ -86,84 +87,25 @@ function StatusWidget:init()
self[1] = statusContainer
end
function StatusWidget:showStatus()
local main_group = VerticalGroup:new{ align = "left" }
local img_width = Screen:scaleBySize(132 * 1.5)
local img_height = Screen:scaleBySize(184 * 1.5)
if Screen:getScreenMode() == "landscape" then
img_width = Screen:scaleBySize(132)
img_height = Screen:scaleBySize(184)
end
local thumb
if self.thumbnail then
thumb = ImageWidget:new{
image = self.thumbnail,
width = img_width,
height = img_height,
autoscale = false,
}
end
function BookStatusWidget:showStatus()
local screen_width = Screen:getWidth()
local cover_with_title_and_author_container = CenterContainer:new{
dimen = Geom:new{ w = screen_width, h = img_height },
}
local cover_with_title_and_author_group = HorizontalGroup:new{ align = "top" }
local span = HorizontalSpan:new{ width = screen_width * 0.05 }
table.insert(cover_with_title_and_author_group, span)
if self.thumbnail then
table.insert(cover_with_title_and_author_group, thumb)
end
table.insert(cover_with_title_and_author_group,
self:generateTitleAuthorProgressGroup(screen_width - span.width - img_width,
img_height,
self.props.title,
self.props.authors,
self.view.state.page, --current page
self.document:getPageCount()))
table.insert(cover_with_title_and_author_container, cover_with_title_and_author_group)
--portrait mode
local rateHeight = Screen:scaleBySize(60)
local statisticsHeight = Screen:scaleBySize(60)
local summaryHeight = Screen:scaleBySize(140)
local statusHeight = Screen:scaleBySize(105)
--landscape mode
if Screen:getScreenMode() == "landscape" then
summaryHeight = Screen:scaleBySize(70)
statusHeight = Screen:scaleBySize(60)
end
local header_group = HorizontalGroup:new{
align = "center",
self:addHeader(screen_width * 0.95, Screen:scaleBySize(15), _("Progress")),
CloseButton:new{ window = self }
return VerticalGroup:new{
align = "left",
OverlapGroup:new{
dimen = Geom:new{ w = screen_width, h = Screen:scaleBySize(30) },
CloseButton:new{ window = self },
},
self:genBookInfoGroup(),
self:genHeader(_("Statistics")),
self:genStatisticsGroup(screen_width),
self:genHeader(_("Review")),
self:genSummaryGroup(screen_width),
self:genHeader(_("Update Status")),
self:generateSwitchGroup(screen_width),
}
table.insert(main_group, header_group)
table.insert(main_group, cover_with_title_and_author_container)
table.insert(main_group, self:addHeader(screen_width, Screen:scaleBySize(25), _("Rate")))
table.insert(main_group, self:generateRateGroup(screen_width, rateHeight, self.summary.rating))
table.insert(main_group, self:addHeader(screen_width, Screen:scaleBySize(35), _("Statistics")))
table.insert(main_group, self:generateStatisticsGroup(screen_width, statisticsHeight,
self:getStatDays(self.stats), self:getStatHours(self.stats), self:getReadPages(self.stats)))
table.insert(main_group, self:addHeader(screen_width, Screen:scaleBySize(35), _("Review")))
table.insert(main_group, self:generateSummaryGroup(screen_width, summaryHeight, self.summary.note))
table.insert(main_group, self:addHeader(screen_width, Screen:scaleBySize(25), _("Update Status")))
table.insert(main_group, self:generateSwitchGroup(screen_width, statusHeight, self.summary.status))
return main_group
end
function StatusWidget:getStatDays(stats)
function BookStatusWidget:getStatDays(stats)
if stats and stats.performance_in_pages then
local dates = {}
for k, v in pairs(stats.performance_in_pages) do
@ -174,129 +116,59 @@ function StatusWidget:getStatDays(stats)
return "none"
end
function StatusWidget:getStatHours(stats)
function BookStatusWidget:getStatHours(stats)
if stats and stats.total_time_in_sec then
return util.secondsToClock(stats.total_time_in_sec, false)
end
return "none"
end
function StatusWidget:getReadPages(stats)
function BookStatusWidget:getReadPages(stats)
if stats and stats.performance_in_pages and stats.pages then
return util.tableSize(stats.performance_in_pages) .. "/" .. stats.pages
end
return "none"
end
function StatusWidget:addHeader(width, height, title)
local group = HorizontalGroup:new{
align = "center",
bordersize = 0,
}
local bold = false
function BookStatusWidget:genHeader(title)
local width, height = Screen:getWidth(), Screen:scaleBySize(35)
local titleWidget = TextWidget:new{
local header_title = TextWidget:new{
text = title,
face = self.large_font_face,
bold = bold,
face = self.medium_font_face,
fgcolor = Blitbuffer.gray(0.4),
}
local titleSize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.large_font_face, title, true, bold)
local lineWidth = ((width - titleSize.x) * 0.5)
local padding_span = HorizontalSpan:new{ width = self.padding }
local line_width = (width - header_title:getSize().w) / 2 - self.padding * 2
local line_container = LeftContainer:new{
dimen = Geom:new{ w = lineWidth, h = height },
dimen = Geom:new{ w = line_width, h = height },
LineWidget:new{
background = Blitbuffer.gray(0.2),
dimen = Geom:new{
w = lineWidth,
w = line_width,
h = 2,
}
}
}
local text_container = CenterContainer:new{
dimen = Geom:new{ w = titleSize.x, h = height },
titleWidget,
}
table.insert(group, line_container)
table.insert(group, text_container)
table.insert(group, line_container)
return group
end
function StatusWidget:generateSwitchGroup(width, height, book_status)
local switch_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
}
local args = {
[1] = "complete",
[2] = "reading",
[3] = "abandoned",
}
local position = 2
for k, v in pairs(args) do
if v == book_status then
position = k
end
end
local config = {
event = "ChangeBookStatus",
default_value = 2,
toggle = {
[1] = _("Complete"),
[2] = _("Reading"),
[3] = _("Abandoned"),
},
args = args,
default_arg = "reading",
values = {
[1] = 1,
[2] = 2,
[3] = 3,
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(25) },
HorizontalGroup:new{
align = "center",
padding_span,
line_container,
padding_span,
header_title,
padding_span,
line_container,
padding_span,
},
name = "book_status",
alternate = false,
enabled = true,
VerticalSpan:new{ width = Screen:scaleBySize(5) },
}
local switch = ToggleSwitch:new{
width = width * 0.6,
default_value = config.default_value,
name = config.name,
name_text = config.name_text,
event = config.event,
toggle = config.toggle,
args = config.args,
alternate = config.alternate,
default_arg = config.default_arg,
values = config.values,
enabled = config.enable,
config = self,
}
switch:setPosition(position)
table.insert(switch_container, switch)
return switch_container
end
function StatusWidget:onConfigChoose(values, name, event, args, events, position)
UIManager:scheduleIn(0.05, function()
if values then
self:onChangeBookStatus(args, position)
end
UIManager:setDirty("all")
end)
end
function StatusWidget:onChangeBookStatus(option_name, option_value)
function BookStatusWidget:onChangeBookStatus(option_name, option_value)
local curr_time = TimeVal:now()
self.summary.status = option_name[option_value]
self.summary.modified = os.date("%Y-%m-%d", curr_time.sec)
@ -304,44 +176,7 @@ function StatusWidget:onChangeBookStatus(option_name, option_value)
return true
end
function StatusWidget:onUpdateNote()
self.summary.note = self.input_note:getText()
self:saveSummary()
return true
end
function StatusWidget:saveSummary()
if self.summary then
self.settings:saveSetting("summary", self.summary)
self.settings:flush()
end
end
function StatusWidget:generateSummaryGroup(width, height, text)
self.input_note = InputText:new{
text = text,
face = self.medium_font_face,
width = width * 0.95,
height = height * 0.55,
scroll = true,
focused = false,
margin = 5,
padding = 0,
parent = self,
hint = _("A few words about the book"),
}
local note_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
self.input_note
}
return note_container
end
function StatusWidget:generateRateGroup(width, height, rating)
function BookStatusWidget:generateRateGroup(width, height, rating)
self.stars_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
}
@ -350,7 +185,7 @@ function StatusWidget:generateRateGroup(width, height, rating)
return self.stars_container
end
function StatusWidget:setStar(num)
function BookStatusWidget:setStar(num)
--clear previous data
self.stars_container:clear()
@ -379,7 +214,106 @@ function StatusWidget:setStar(num)
return true
end
function StatusWidget:generateStatisticsGroup(width, height, days, average, pages)
function BookStatusWidget:genBookInfoGroup()
local screen_width = Screen:getWidth()
local split_span_width = screen_width * 0.05
local img_width, img_height
if Screen:getScreenMode() == "landscape" then
img_width = Screen:scaleBySize(132)
img_height = Screen:scaleBySize(184)
else
img_width = Screen:scaleBySize(132 * 1.5)
img_height = Screen:scaleBySize(184 * 1.5)
end
local height = img_height
local width = screen_width - split_span_width - img_width
-- title
local book_meta_info_group = VerticalGroup:new{
align = "center",
VerticalSpan:new{ width = height * 0.2 },
TextBoxWidget:new{
text = self.props.title,
width = width,
face = self.medium_font_face,
alignment = "center",
},
}
-- author
local text_author = TextWidget:new{
text = self.props.authors,
face = self.small_font_face,
padding = 2,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_author:getSize().h },
text_author
}
)
-- progress bar
local total_pages = self.document:getPageCount()
local read_percentage = self.view.state.page / total_pages
local progress_bar = ProgressWidget:new{
width = width * 0.7,
height = Screen:scaleBySize(10),
percentage = read_percentage,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = progress_bar:getSize().h },
progress_bar
}
)
-- complete text
local text_complete = TextWidget:new{
text = template(_("%1% Completed"),
string.format("%1.f", read_percentage * 100)),
face = self.small_font_face,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_complete:getSize().h },
text_complete
}
)
-- rating
table.insert(book_meta_info_group,
VerticalSpan:new{ width = Screen:scaleBySize(30) })
local rateHeight = Screen:scaleBySize(60)
table.insert(book_meta_info_group,
self:generateRateGroup(screen_width, rateHeight, self.summary.rating))
-- build the final group
local book_info_group = HorizontalGroup:new{
align = "top",
HorizontalSpan:new{ width = split_span_width }
}
-- thumbnail
if self.thumbnail then
table.insert(book_info_group, ImageWidget:new{
image = self.thumbnail,
width = img_width,
height = img_height,
autoscale = false,
})
end
table.insert(book_info_group, CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
book_meta_info_group,
})
return CenterContainer:new{
dimen = Geom:new{ w = screen_width, h = img_height },
book_info_group,
}
end
function BookStatusWidget:genStatisticsGroup(width)
local height = Screen:scaleBySize(60)
local statistics_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
}
@ -414,27 +348,26 @@ function StatusWidget:generateStatisticsGroup(width, height, days, average, page
}
}
local data_group = HorizontalGroup:new{
align = "center",
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
text = days,
text = self:getStatDays(self.stats),
face = self.medium_font_face,
},
},
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
text = average,
text = self:getStatHours(self.stats),
face = self.medium_font_face,
},
},
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
text = pages,
text = self:getReadPages(self.stats),
face = self.medium_font_face,
}
}
@ -447,82 +380,130 @@ function StatusWidget:generateStatisticsGroup(width, height, days, average, page
return statistics_container
end
function StatusWidget:generateTitleAuthorProgressGroup(width, height, title, authors, current_page, total_pages)
function BookStatusWidget:genSummaryGroup(width)
local height
if Screen:getScreenMode() == "landscape" then
height = Screen:scaleBySize(60)
else
height = Screen:scaleBySize(130)
end
local title_author_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
local text_padding = 5
self.input_note = InputText:new{
text = self.summary.note,
face = self.medium_font_face,
width = width - self.padding * 3,
height = height * 0.75,
scroll = true,
bordersize = 2,
focused = false,
padding = text_padding,
parent = self,
hint = _("A few words about the book"),
}
local title_author_progressbar_group = VerticalGroup:new{
align = "center",
VerticalSpan:new{ width = height * 0.2 },
TextBoxWidget:new{
text = title,
width = width,
face = self.medium_font_face,
alignment = "center",
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(5) },
CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
self.input_note
}
}
local text_author = TextWidget:new{
text = authors,
face = self.small_font_face,
padding = 2,
}
end
local author_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = text_author:getSize().h },
text_author
}
function BookStatusWidget:onUpdateNote()
self.summary.note = self.input_note:getText()
self:saveSummary()
return true
end
table.insert(title_author_progressbar_group, author_container)
function BookStatusWidget:saveSummary()
if self.summary then
self.settings:saveSetting("summary", self.summary)
self.settings:flush()
end
end
function BookStatusWidget:generateSwitchGroup(width)
local height
if Screen:getScreenMode() == "landscape" then
-- landscape mode
height = Screen:scaleBySize(60)
else
-- portrait mode
height = Screen:scaleBySize(105)
end
local read_percentage = current_page / total_pages
local progress_height = Screen:scaleBySize(10)
local args = { "complete", "reading", "abandoned" }
local progress_bar = ProgressWidget:new{
width = width * 0.7,
height = progress_height,
percentage = read_percentage,
ticks = {},
tick_width = 0,
last = total_pages,
local current_status = self.summary.status
local position = 2
for k, v in pairs(args) do
if v == current_status then
position = k
end
end
local config = {
event = "ChangeBookStatus",
default_value = 2,
args = args,
default_arg = "reading",
toggle = { _("Complete"), _("Reading"), _("Abandoned") },
values = { 1, 2, 3 },
name = "book_status",
alternate = false,
enabled = true,
}
table.insert(title_author_progressbar_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = progress_bar:getSize().h },
progress_bar
}
)
local text_complete = TextWidget:new{
text = template(_("%1% Completed"),
string.format("%1.f", read_percentage * 100)),
face = self.small_font_face,
local switch = ToggleSwitch:new{
width = width * 0.6,
default_value = config.default_value,
name = config.name,
name_text = config.name_text,
event = config.event,
toggle = config.toggle,
args = config.args,
alternate = config.alternate,
default_arg = config.default_arg,
values = config.values,
enabled = config.enable,
config = self,
}
switch:setPosition(position)
local progress_bar_text_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = text_complete:getSize().h },
text_complete
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(10) },
CenterContainer:new{
ignore = "height",
dimen = Geom:new{ w = width, h = height },
switch,
}
}
end
table.insert(title_author_progressbar_group, progress_bar_text_container)
table.insert(title_author_container, title_author_progressbar_group)
return title_author_container
function BookStatusWidget:onConfigChoose(values, name, event, args, events, position)
UIManager:scheduleIn(0.05, function()
if values then
self:onChangeBookStatus(args, position)
end
UIManager:setDirty("all")
end)
end
function StatusWidget:onAnyKeyPressed()
function BookStatusWidget:onAnyKeyPressed()
return self:onClose()
end
function StatusWidget:onClose()
function BookStatusWidget:onClose()
self:saveSummary()
UIManager:setDirty("all")
UIManager:close(self)
return true
end
function StatusWidget:getStatisticsSettings()
function BookStatusWidget:getStatisticsSettings()
if self.settings then
local stats = self.settings:readSetting("stats")
if stats then
@ -534,8 +515,7 @@ function StatusWidget:getStatisticsSettings()
end
end
function StatusWidget:onSwitchFocus(inputbox)
function BookStatusWidget:onSwitchFocus(inputbox)
self.note_dialog = InputDialog:new{
title = "Note",
input = self.input_note:getText(),
@ -571,10 +551,9 @@ function StatusWidget:onSwitchFocus(inputbox)
UIManager:show(self.note_dialog)
end
function StatusWidget:closeInputDialog()
function BookStatusWidget:closeInputDialog()
self.note_dialog:onClose()
UIManager:close(self.note_dialog)
end
return StatusWidget
return BookStatusWidget

@ -14,8 +14,11 @@ Example:
local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local TextWidget = require("ui/widget/textwidget")
local GestureRange = require("ui/gesturerange")
local Screen = require("device").screen
local Font = require("ui/font")
local CloseButton = InputContainer:new{
@ -28,18 +31,24 @@ function CloseButton:init()
text = "×",
face = Font:getFace("cfont", 32),
}
local padding_span = HorizontalSpan:new{ width = Screen:scaleBySize(14) }
self[1] = FrameContainer:new{
bordersize = 0,
padding = 0,
text_widget
HorizontalGroup:new{
padding_span,
text_widget,
padding_span,
}
}
self.dimen = text_widget:getSize()
self.ges_events.Close = {
GestureRange:new{
ges = "tap",
range = self.dimen,
-- x and y coordinates for the widget is only known after the it is
-- drawn. so use callback to get range at runtime.
range = function() return self.dimen end,
},
doc = "Tap on close button",
}

@ -126,7 +126,7 @@ function DictQuickLookup:update()
text = self.dictionary,
face = self.title_face,
bold = true,
width = self.width - self.button_padding,
width = self.width,
}
}
-- lookup word
@ -218,7 +218,10 @@ function DictQuickLookup:update()
}
self.dict_bar = OverlapGroup:new{
dimen = {w = button_table:getSize().w, h = self.dict_title:getSize().h},
dimen = {
w = button_table:getSize().w + self.button_padding,
h = self.dict_title:getSize().h
},
self.dict_title,
}

@ -100,7 +100,7 @@ function InputText:initTextBox(text)
text_widget,
}
self.dimen = self[1]:getSize()
-- FIXME: self.parent is not always in the widget statck (BookStatusWidget)
UIManager:setDirty(self.parent, function()
return "ui", self[1].dimen
end)

@ -77,6 +77,7 @@ function KeyValueTitle:init()
else
show_title_txt = self.title
end
-- title and close button
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
@ -85,12 +86,14 @@ function KeyValueTitle:init()
},
self.close_button,
})
-- page count and separation line
self.page_cnt = FrameContainer:new{
padding = 4,
margin = 0,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
overlap_offset = {0, -18},
-- overlap offset x will be updated in setPageCount method
overlap_offset = {0, -15},
TextWidget:new{
text = "", -- page count
fgcolor = Blitbuffer.COLOR_GREY,
@ -117,8 +120,7 @@ function KeyValueTitle:setPageCount(curr, total)
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.page_cnt.overlap_offset[1] = (self.width - self.page_cnt:getSize().w - 10)
self.title_bottom[2] = self.page_cnt
end

@ -1,10 +1,36 @@
--[[--
Widget for displaying progress bar.
Configurable attributes:
* width
* height
* margin_v -- vertical margin for solid infill
* margin_h -- horizontal margin for solid infill
* radius
* bordersize
* bordercolor
* bgcolor
* rectcolor -- infill color
* ticks (list) -- default to nil, use this if you want to insert markers
* tick_width
* last -- maximum tick
Example:
local foo_bar = ProgressWidget:new{
width = 400,
height = 10,
percentage = 50/100,
}
UIManager:show(foo_bar)
]]
local Widget = require("ui/widget/widget")
local Geom = require("ui/geometry")
local Blitbuffer = require("ffi/blitbuffer")
--[[
ProgressWidget shows a progress bar
--]]
local ProgressWidget = Widget:new{
width = nil,
height = nil,
@ -16,7 +42,7 @@ local ProgressWidget = Widget:new{
bgcolor = Blitbuffer.COLOR_WHITE,
rectcolor = Blitbuffer.gray(0.7),
percentage = nil,
ticks = {},
ticks = nil,
tick_width = 3,
last = nil,
}
@ -32,18 +58,26 @@ function ProgressWidget:paintTo(bb, x, y)
w = my_size.w,
h = my_size.h
}
-- fill background
bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.bgcolor, self.radius)
bb:paintBorder(x, y, my_size.w, my_size.h,
self.bordersize, self.bordercolor, self.radius)
bb:paintRect(x+self.margin_h, y+self.margin_v+self.bordersize,
(my_size.w-2*self.margin_h)*self.percentage,
(my_size.h-2*(self.margin_v+self.bordersize)), self.rectcolor)
for i=1, #self.ticks do
local page = self.ticks[i]
bb:paintRect(
-- paint border
bb:paintBorder(x, y,
my_size.w, my_size.h,
self.bordersize, self.bordercolor, self.radius)
-- paint percentage infill
bb:paintRect(x+self.margin_h, math.ceil(y+self.margin_v+self.bordersize),
math.ceil((my_size.w-2*self.margin_h)*self.percentage),
my_size.h-2*(self.margin_v+self.bordersize), self.rectcolor)
if self.ticks then
for i=1, #self.ticks do
local page = self.ticks[i]
bb:paintRect(
x + (my_size.w-2*self.margin_h)*(page/self.last),
y + self.margin_v + self.bordersize, self.tick_width,
(my_size.h-2*(self.margin_v+self.bordersize)), self.bordercolor)
y + self.margin_v + self.bordersize,
self.tick_width,
my_size.h-2*(self.margin_v+self.bordersize),
self.bordercolor)
end
end
end

@ -309,7 +309,9 @@ OPTIONS:
if [ ! -z $2 ]; then
test_path="${test_path}/$2"
fi
busted --lua=./luajit ${opts} -o ./spec/$1/unit/verbose_print --exclude-tags=notest ${test_path}
busted --lua=./luajit ${opts} \
-o ./spec/$1/unit/verbose_print \
--exclude-tags=notest ${test_path}
popd
}

@ -0,0 +1,39 @@
require("commonrequire")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
describe("gesturerange module", function()
it("should match tap event within range", function()
local g = GestureRange:new{
ges = "tap",
range = Geom:new{ x = 0, y = 0, w = 200, h = 200},
}
assert.truthy(g:match({
ges = "tap",
pos = Geom:new{ x = 1, y = 1, w = 0, h = 0 },
}))
end)
it("should not match tap event outside of range", function()
local g = GestureRange:new{
ges = "tap",
range = Geom:new{ x = 0, y = 0, w = 100, h = 100},
}
assert.falsy(g:match({
ges = "tap",
pos = Geom:new{ x = 105, y = 1, w = 0, h = 0 },
}))
end)
it("should match any event within nil range", function()
local g = GestureRange:new{
ges = "tap",
range = nil,
}
assert.truthy(g:match({
ges = "tap",
pos = Geom:new{ x = 1, y = 1, w = 1000000000000000000, h = 100 },
}))
end)
end)

@ -113,6 +113,25 @@ describe("UIManager spec", function()
assert.are.same('quux', UIManager._task_queue[5].action)
end)
it("should unschedule all the tasks with the same action", function()
local now = { util.gettime() }
local noop1 = function() end
UIManager:quit()
UIManager._task_queue = {
{ time = {now[1] - 15, now[2] }, action = '3' },
{ time = {now[1] - 10, now[2] }, action = '1' },
{ time = {now[1], now[2] - 6 }, action = '3' },
{ time = {now[1], now[2] - 5 }, action = '2' },
{ time = now, action = '3' },
}
-- insert into the tail slot
UIManager:unschedule('3')
assert.are.same({
{ time = {now[1] - 10, now[2] }, action = '1' },
{ time = {now[1], now[2] - 5 }, action = '2' },
}, UIManager._task_queue)
end)
it("should not have race between unschedule and _checkTasks", function()
local now = { util.gettime() }
local run_count = 0

@ -340,36 +340,57 @@ local TestInputText = InputText:new{
-----------------------------------------------------
-- key value page
-----------------------------------------------------
local KeyValuePage = require("ui/widget/keyvaluepage")
local kvp = KeyValuePage:new{
title = 'Statistics This is a very very log item whose length should exceed the width of the men',
kv_pairs = {
{"1 Current period", "00:00:00"},
{"This is a very very log item whose length should exceed the width of the menu.", "value"},
{"2 Time to read", "00:00:00 00:00:00 00:00:00 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"},
},
}
function testKeyValuePage()
local KeyValuePage = require("ui/widget/keyvaluepage")
local kvp = KeyValuePage:new{
title = 'Statistics This is a very very log item whose length should exceed the width of the men',
kv_pairs = {
{"1 Current period", "00:00:00"},
{"This is a very very log item whose length should exceed the width of the menu.", "value"},
{"2 Time to read", "00:00:00 00:00:00 00:00:00 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"},
},
}
UIManager:show(kvp)
end
function testBookStatus()
-- doc = DocumentRegistry:openDocument("spec/front/unit/data/juliet.epub")
doc = DocumentRegistry:openDocument("spec/front/unit/data/2col.pdf")
reader = ReaderUI:new{
dialog = readerwindow,
dimen = Geom:new{ w = Screen:getWidth() - 100, h = Screen:getHeight() - 100 },
document = doc
}
local status_page = require("ui/widget/bookstatuswidget"):new {
thumbnail = doc:getCoverPageImage(),
props = doc:getProps(),
document = doc,
view = reader.view,
}
UIManager:show(status_page)
end
-----------------------------------------------------------------------
-- you may want to uncomment following show calls to see the changes
@ -385,6 +406,7 @@ UIManager:show(Clock:new())
--UIManager:show(keyboard)
--UIManager:show(TestInputText)
--TestInputText:onShowKeyboard()
--UIManager:show(kvp)
-- testKeyValuePage()
testBookStatus()
UIManager:run()

Loading…
Cancel
Save