CoverBrowser Mosaic: improve book status, floating progress bar (#9939)

- New dogear icons in Mosaic cover view to indicate each
  possible book status: 'Reading', 'On hold', 'Finished'
- Progress bar redesigned to be floating, taller, thicker
  bordered in Mosaic cover view
- Don't show progress bar if book is finished
- FakeCover bottom text (filename) adjusted to not overlap
  with progress bar and dogear if they exist
- Mosaic book shortcut letter moved from bottom left to
  top left
reviewable/pr10135/r1
melyux 1 year ago committed by GitHub
parent 706c8c5610
commit e55b60175b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -278,7 +278,7 @@ function CoverBrowser:addToMainMenu(menu_items)
end,
},
{
text = _("Show hint for opened books in history"),
text = _("Show hint for book status in history"),
checked_func = function() return BookInfoManager:getSetting("history_hint_opened") end,
callback = function()
if BookInfoManager:getSetting("history_hint_opened") then
@ -290,7 +290,7 @@ function CoverBrowser:addToMainMenu(menu_items)
end,
},
{
text = _("Show hint for opened books in favorites"),
text = _("Show hint for book status in favorites"),
checked_func = function() return BookInfoManager:getSetting("collections_hint_opened") end,
callback = function()
if BookInfoManager:getSetting("collections_hint_opened") then

@ -44,6 +44,9 @@ local BookInfoManager = require("bookinfomanager")
-- recreated if height changes)
local corner_mark_size = -1
local corner_mark
local reading_mark
local abandoned_mark
local complete_mark
local progress_widget
-- ItemShortCutIcon (for keyboard navigation) is private to menu.lua and can't be accessed,
@ -102,6 +105,7 @@ local FakeCover = FrameContainer:extend{
padding = 0,
bordersize = Size.border.thin,
dim = nil,
bottom_right_compensate = false,
-- Provided filename, title and authors should not be BD wrapped
filename = nil,
file_deleted = nil,
@ -251,7 +255,7 @@ function FakeCover:init()
text = filename,
lang = self.book_lang, -- might as well use it for filename
face = Font:getFace("cfont", math.max(self.filename_font_max - sizedec, self.filename_font_min)),
width = text_width,
width = self.bottom_right_compensate and width - 2 * corner_mark_size or text_width,
alignment = "center",
}
texts_height = texts_height + filename_wg:getSize().h
@ -383,6 +387,7 @@ function MosaicMenuItem:init()
self.detail = self.text
self.percent_finished = nil
self.status = nil
-- we need this table per-instance, so we declare it here
self.ges_events = {
@ -559,6 +564,42 @@ function MosaicMenuItem:update()
end
if bookinfo then -- This book is known
-- Current page / pages are available or more accurate in .sdr/metadata.lua
-- We use a cache (cleaned at end of this browsing session) to store
-- page, percent read and book status from sidecar files, to avoid
-- re-parsing them when re-rendering a visited page
-- This cache is shared with ListMenu, so we need to fill it with the same
-- info here than there, even if we don't need them all here.
if not self.menu.cover_info_cache then
self.menu.cover_info_cache = {}
end
local percent_finished, status
local pages = bookinfo.pages
if DocSettings:hasSidecarFile(self.filepath) then
self.been_opened = true
if self.menu.cover_info_cache[self.filepath] then
pages, percent_finished, status = unpack(self.menu.cover_info_cache[self.filepath]) -- luacheck: no unused
else
local docinfo = DocSettings:open(self.filepath)
-- We can get nb of page in the new 'doc_pages' setting, or from the old 'stats.page'
if docinfo.data.doc_pages then
pages = docinfo.data.doc_pages
elseif docinfo.data.stats and docinfo.data.stats.pages then
if docinfo.data.stats.pages ~= 0 then -- crengine with statistics disabled stores 0
pages = docinfo.data.stats.pages
end
end
if docinfo.data.summary and docinfo.data.summary.status then
status = docinfo.data.summary.status
end
percent_finished = docinfo.data.percent_finished
self.menu.cover_info_cache[self.filepath] = {pages, percent_finished, status}
end
end
self.percent_finished = percent_finished
self.status = status
self.show_progress_bar = self.status ~= "complete" and BookInfoManager:getSetting("show_progress_in_mosaic") and self.percent_finished
local cover_bb_used = false
self.bookinfo_found = true
-- For wikipedia saved as epub, we made a cover from the 1st pic of the page,
@ -622,6 +663,12 @@ function MosaicMenuItem:update()
end
end
end
local bottom_pad = Size.padding.default
if self.show_progress_bar and self.do_hint_opened then
bottom_pad = corner_mark_size + Screen:scaleBySize(2)
elseif self.show_progress_bar then
bottom_pad = corner_mark_size - Screen:scaleBySize(2)
end
widget = CenterContainer:new{
dimen = dimen,
FakeCover:new{
@ -636,6 +683,8 @@ function MosaicMenuItem:update()
authors_add = not bookinfo.ignore_meta and authors_add,
book_lang = not bookinfo.ignore_meta and bookinfo.language,
file_deleted = self.file_deleted,
bottom_pad = bottom_pad,
bottom_right_compensate = not self.show_progress_bar and self.do_hint_opened,
}
}
end
@ -647,43 +696,6 @@ function MosaicMenuItem:update()
if bookinfo.description then
self.has_description = true
end
-- Current page / pages are available or more accurate in .sdr/metadata.lua
-- We use a cache (cleaned at end of this browsing session) to store
-- page, percent read and book status from sidecar files, to avoid
-- re-parsing them when re-rendering a visited page
-- This cache is shared with ListMenu, so we need to fill it with the same
-- info here than there, even if we don't need them all here.
if not self.menu.cover_info_cache then
self.menu.cover_info_cache = {}
end
local percent_finished, status
local pages = bookinfo.pages
if DocSettings:hasSidecarFile(self.filepath) then
self.been_opened = true
if self.menu.cover_info_cache[self.filepath] then
pages, percent_finished, status = unpack(self.menu.cover_info_cache[self.filepath]) -- luacheck: no unused
else
local docinfo = DocSettings:open(self.filepath)
-- We can get nb of page in the new 'doc_pages' setting, or from the old 'stats.page'
if docinfo.data.doc_pages then
pages = docinfo.data.doc_pages
elseif docinfo.data.stats and docinfo.data.stats.pages then
if docinfo.data.stats.pages ~= 0 then -- crengine with statistics disabled stores 0
pages = docinfo.data.stats.pages
end
end
if docinfo.data.summary and docinfo.data.summary.status then
status = docinfo.data.summary.status
end
percent_finished = docinfo.data.percent_finished
self.menu.cover_info_cache[self.filepath] = {pages, percent_finished, status}
end
end
if status == "completed" then
percent_finished = 100
end
self.percent_finished = percent_finished
else -- bookinfo not found
if self.init_done then
-- Non-initial update(), but our widget is still not found:
@ -740,7 +752,7 @@ function MosaicMenuItem:paintTo(bb, x, y)
-- to which we paint over the shortcut icon
if self.shortcut_icon then
-- align it on bottom left corner of widget
-- align it on top left corner of widget
local target = self
local ix
if BD.mirroredUILayout() then
@ -748,13 +760,11 @@ function MosaicMenuItem:paintTo(bb, x, y)
else
ix = 0
end
local iy = target.dimen.h - self.shortcut_icon.dimen.h
local iy = 0
self.shortcut_icon:paintTo(bb, x+ix, y+iy)
end
local show_progress_in_mosaic = BookInfoManager:getSetting("show_progress_in_mosaic")
-- to which we paint over a dogear if needed
if not show_progress_in_mosaic and corner_mark and self.do_hint_opened and self.been_opened then
if self.do_hint_opened and self.been_opened then
-- align it on bottom right corner of sub-widget
local target = self[1][1][1]
local ix
@ -765,15 +775,33 @@ function MosaicMenuItem:paintTo(bb, x, y)
end
local iy = self.height - math.ceil((self.height - target.dimen.h)/2) - corner_mark:getSize().h
-- math.ceil() makes it looks better than math.floor()
if self.status == "abandoned" then
corner_mark = abandoned_mark
elseif self.status == "complete" then
corner_mark = complete_mark
else
corner_mark = reading_mark
end
corner_mark:paintTo(bb, x+ix, y+iy)
end
if show_progress_in_mosaic and self.percent_finished then
if self.show_progress_bar then
local cover_item = self[1][1][1]
local width = math.min(self.width * 0.60, cover_item.width)
progress_widget.width = width
local pos_x = x + self.width - progress_widget.width - math.ceil((self.width - cover_item.width) / 2) - progress_widget.bordersize
local pos_y = y + self.height - progress_widget.height - math.ceil((self.height - cover_item.height) / 2)
local progress_widget_margin = math.floor((corner_mark_size - progress_widget.height) / 2)
progress_widget.width = cover_item.width - 2*progress_widget_margin
local pos_x = x + math.ceil((self.width - progress_widget.width) / 2)
if self.do_hint_opened then
progress_widget.width = progress_widget.width - corner_mark_size
if BD.mirroredUILayout() then
pos_x = pos_x + corner_mark_size
end
end
local pos_y = y + self.height - math.ceil((self.height - cover_item.height) / 2) - corner_mark_size + progress_widget_margin
if self.status == "abandoned" then
progress_widget.fillcolor = Blitbuffer.COLOR_GRAY_6
else
progress_widget.fillcolor = Blitbuffer.COLOR_BLACK
end
progress_widget:setPercentage(self.percent_finished)
progress_widget:paintTo(bb, pos_x, pos_y)
end
@ -886,18 +914,32 @@ function MosaicMenu:_recalculateDimen()
-- Create or replace corner_mark if needed
-- 1/12 (larger) or 1/16 (smaller) of cover looks allright
local mark_size = math.floor(math.min(self.item_width, self.item_height) / 16)
local mark_size = math.floor(math.min(self.item_width, self.item_height) / 8)
if mark_size ~= corner_mark_size then
corner_mark_size = mark_size
if corner_mark then
corner_mark:free()
reading_mark:free()
abandoned_mark:free()
complete_mark:free()
end
corner_mark = IconWidget:new{
icon = "dogear.opaque",
rotation_angle = BD.mirroredUILayout() and 180 or 270,
reading_mark = IconWidget:new{
icon = "dogear.reading",
rotation_angle = BD.mirroredUILayout() and 270 or 0,
width = corner_mark_size,
height = corner_mark_size,
}
abandoned_mark = IconWidget:new{
icon = BD.mirroredUILayout() and "dogear.abandoned.rtl" or "dogear.abandoned",
width = corner_mark_size,
height = corner_mark_size,
}
complete_mark = IconWidget:new{
icon = BD.mirroredUILayout() and "dogear.complete.rtl" or "dogear.complete",
alpha = true,
width = corner_mark_size,
height = corner_mark_size,
}
corner_mark = reading_mark
end
-- Create or replace progress_widget if needed
@ -907,11 +949,11 @@ function MosaicMenu:_recalculateDimen()
bgcolor = Blitbuffer.COLOR_WHITE,
fillcolor = Blitbuffer.COLOR_BLACK,
bordercolor = Blitbuffer.COLOR_BLACK,
height = Screen:scaleBySize(6),
height = Screen:scaleBySize(8),
margin_h = Screen:scaleBySize(1),
width = progress_bar_width,
radius = Size.border.thin,
bordersize = Size.border.thin,
bordersize = Size.border.default,
}
end
end

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="background" fill="#ffffff" stroke="none" d="M 0 0 L 48 0 L 48 48 L 0 48 Z"/>
<polygon points="1,1 47,1 47,47" fill="none" stroke="#000000" stroke-width="2"/>
<path id="pause-left" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="butt" d="M 40 6 L 40 21"/>
<path id="pause-right" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="butt" stroke-linejoin="bevel" d="M 31 6 L 31 21"/>
</svg>

After

Width:  |  Height:  |  Size: 604 B

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="background" fill="#ffffff" stroke="none" d="M 0 0 L 48 0 L 48 48 L 0 48 Z"/>
<polygon points="1,47 1,1 47,1" fill="none" stroke="#000000" stroke-width="2"/>
<path id="pause-left" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="butt" d="M 8 6 L 8 21"/>
<path id="pause-right" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="butt" stroke-linejoin="bevel" d="M 17 6 L 17 21"/>
</svg>

After

Width:  |  Height:  |  Size: 601 B

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<polygon id="triangle-and-background" points="47,47 1,47 1,1" fill="#ffffff" stroke="#000000" stroke-width="2"/>
<path id="checkmark" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="square" stroke-linejoin="miter" d="M 21 30 L 10 41 L 6 37"/>
</svg>

After

Width:  |  Height:  |  Size: 438 B

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<polygon id="triangle-and-background" points="1,47 47,47 47,1" fill="#ffffff" stroke="#000000" stroke-width="2"/>
<path id="checkmark" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="square" stroke-linejoin="miter" d="M 38 28 L 27 39 L 23 35"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="background" fill="#ffffff" stroke="none" d="M 0 0 L 48 0 L 48 48 L 0 48 Z"/>
<polygon points="1,47 1,1 47,1" fill="none" stroke="#000000" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 348 B

Loading…
Cancel
Save