mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 08:21:39 -06:00
e0ce6d3348
Keep long dashboard highlights readable while preserving quick access to book details.
140 lines
5.4 KiB
Lua
140 lines
5.4 KiB
Lua
--[[--
|
|
The Highlight of the day drawer. The dashboard tile is deliberately concise;
|
|
this sheet keeps the full passage readable and leaves book details one tap away.
|
|
Long passages turn page by page inside the drawer.
|
|
]]
|
|
|
|
local Device = require("device")
|
|
local TextBoxWidget = require("ui/widget/textboxwidget")
|
|
local UIManager = require("ui/uimanager")
|
|
local _ = require("gettext")
|
|
|
|
local BoardMetrics = require("bookorbit_board_metrics")
|
|
local BoardUI = require("bookorbit_board_ui")
|
|
local DialogUI = require("bookorbit_dialog_ui")
|
|
local TextPages = require("bookorbit_text_pages")
|
|
|
|
local INK = BoardMetrics.INK
|
|
local px, lh = BoardMetrics.px, BoardMetrics.lh
|
|
local text, vstack, hstack, space = BoardUI.text, BoardUI.vstack, BoardUI.hstack, BoardUI.space
|
|
|
|
local HighlightSheet = {}
|
|
|
|
local BODY_SIZE = 16
|
|
|
|
local function hOf(widget) return widget:getSize().h end
|
|
|
|
function HighlightSheet.pageWindow(total_lines, available_height, line_height, index)
|
|
total_lines = math.max(1, tonumber(total_lines) or 1)
|
|
line_height = math.max(1, tonumber(line_height) or 1)
|
|
local per_page = math.max(1, math.floor(math.max(1, available_height) / line_height))
|
|
local count = math.max(1, math.ceil(total_lines / per_page))
|
|
index = math.max(1, math.min(count, tonumber(index) or 1))
|
|
return {
|
|
count = count,
|
|
index = index,
|
|
per_page = per_page,
|
|
first_line = (index - 1) * per_page + 1,
|
|
height = math.min(total_lines, per_page) * line_height,
|
|
}
|
|
end
|
|
|
|
local function chapterLine(highlight, w)
|
|
local chapter = type(highlight.chapterTitle) == "string" and highlight.chapterTitle:match("^%s*(.-)%s*$") or nil
|
|
if not chapter or chapter == "" then return nil end
|
|
return text(chapter, { s = 13, b = true, col = INK.g3, w = w, data = true })
|
|
end
|
|
|
|
local function buildBody(page, w, max_body_h)
|
|
local highlight = page.highlight
|
|
local head = DialogUI.titleRow(w, _("Highlight of the day"), highlight.bookTitle)
|
|
local chapter = chapterLine(highlight, w)
|
|
local details = highlight.bookId and DialogUI.pillRow(w, {
|
|
{ label = _("Book details"), icon = "book-open-text", kind = "outline", action = { kind = "details" } },
|
|
}) or nil
|
|
local gap = px(14)
|
|
local line_height = lh(BODY_SIZE)
|
|
local bar = math.max(2, px(3))
|
|
local quote_gap = px(14)
|
|
local quote_w = math.max(1, w - bar - quote_gap)
|
|
local total_lines = TextPages.linesNeeded(highlight.text or "", { s = BODY_SIZE, serif = true, i = true }, quote_w)
|
|
|
|
local function fixedHeight(with_pager)
|
|
local fixed_items = { head }
|
|
if chapter then table.insert(fixed_items, chapter) end
|
|
if with_pager then table.insert(fixed_items, true) end
|
|
if details then table.insert(fixed_items, details) end
|
|
local height = 0
|
|
for _i, item in ipairs(fixed_items) do
|
|
height = height + (item == true and px(40) or hOf(item))
|
|
end
|
|
return height + #fixed_items * gap
|
|
end
|
|
|
|
local window = HighlightSheet.pageWindow(total_lines, max_body_h - fixedHeight(false), line_height, page.index)
|
|
if window.count > 1 then
|
|
window = HighlightSheet.pageWindow(total_lines, max_body_h - fixedHeight(true), line_height, page.index)
|
|
end
|
|
page.index = window.index
|
|
page.count = window.count
|
|
|
|
local quote = TextBoxWidget:new{
|
|
text = highlight.text or "",
|
|
face = BoardMetrics.face(BODY_SIZE, "serif_italic"),
|
|
width = quote_w,
|
|
height = window.height,
|
|
virtual_line_num = window.first_line,
|
|
fgcolor = INK.black,
|
|
bgcolor = INK.white,
|
|
}
|
|
local quote_block = hstack({ w = w, valign = "top" }, {
|
|
BoardUI.rect(bar, window.height, INK.black, math.floor(bar / 2)),
|
|
space(quote_gap, 1),
|
|
quote,
|
|
})
|
|
local items = { head, quote_block }
|
|
if chapter then table.insert(items, chapter) end
|
|
if window.count > 1 then table.insert(items, TextPages.pager(w, window.index, window.count)) end
|
|
if details then table.insert(items, details) end
|
|
return items
|
|
end
|
|
|
|
local function turn(page, delta)
|
|
local next_index = math.max(1, math.min(page.count or 1, page.index + delta))
|
|
if next_index == page.index then return end
|
|
page.index = next_index
|
|
page:refresh(Device:hasEinkScreen() and "partial" or "ui")
|
|
end
|
|
|
|
function HighlightSheet.open(catalog, highlight)
|
|
if type(highlight) ~= "table" then return nil end
|
|
return DialogUI.open{
|
|
name = "bookorbit_highlight_of_the_day",
|
|
build = function(page, sw, sh)
|
|
return DialogUI.sheet(page, sw, sh, function(w, max_body_h)
|
|
return buildBody(page, w, max_body_h)
|
|
end, { pop_w = 520 })
|
|
end,
|
|
on_action = function(page, action)
|
|
if action.kind == "page" then
|
|
turn(page, action.delta)
|
|
elseif action.kind == "details" and page.highlight.bookId then
|
|
local book_id = page.highlight.bookId
|
|
page:close()
|
|
UIManager:tickAfterNext(function() catalog:loadBookDetail(book_id) end)
|
|
end
|
|
return true
|
|
end,
|
|
on_swipe = function(page, ges)
|
|
if ges.direction == "west" then turn(page, 1) return true end
|
|
if ges.direction == "east" then turn(page, -1) return true end
|
|
return false
|
|
end,
|
|
on_page_key = function(page, delta) turn(page, delta) end,
|
|
highlight = highlight,
|
|
index = 1,
|
|
}
|
|
end
|
|
|
|
return HighlightSheet
|