Ctrl K
ComunidadGuías…

koreader-plugin/bookorbit.koplugin/bookorbit_highlight_sheet.lua

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
--[[--
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