Ctrl K
ComunidadGuías…

koreader-plugin/bookorbit.koplugin/bookorbit_book_peek.lua

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

Archivo original ↗Preguntar a KiBot
--[[--
The sheet a long-press on a book opens, anywhere in the catalog.

The book's cover, where it stands and whether it is on this device, then the
two things a long-press is for (Read or Download, and Details), then About,
Genres & tags and either Download options or Remove from this device. Book
info is not a separate door: Details opens the detail page, whose second page
holds those facts.
]]

local UIManager = require("ui/uimanager")
local T = require("ffi/util").template
local _ = require("gettext")

local BoardMetrics = require("bookorbit_board_metrics")
local CatalogUtil = require("bookorbit_catalog_util")
local DetailData = require("bookorbit_detail_data")
local DialogUI = require("bookorbit_dialog_ui")
local MenuUI = require("bookorbit_menu_ui")

local INK = BoardMetrics.INK

local BookPeek = {}

-- "Books › Standalone": the last two folders of where a download lands.
function BookPeek.folderLabel(path)
    if type(path) ~= "string" or path == "" then return nil end
    local parts = {}
    for part in path:gmatch("[^/]+") do table.insert(parts, part) end
    if #parts == 0 then return "/" end
    return table.concat(parts, " › ", math.max(1, #parts - 1))
end

-- What the page knows about the book, as plain data the sheet draws.
function BookPeek.data(catalog, detail, opts)
    opts = opts or {}
    catalog:refreshOnDevice()
    local supported = catalog:supportedFiles(detail)
    local read_path = catalog:detailReadPath(detail)
    local file = #supported > 0 and catalog:nextDownloadFile(supported) or nil
    local authors = {}
    for _i, a in ipairs(detail.authors or {}) do
        local name = CatalogUtil.cleanInlineText(a)
        if name then table.insert(authors, name) end
    end
    local description = DetailData.cleanDescription(detail.description)
    local status = detail.readStatus or "unread"
    local pct = tonumber(detail.progressPercentage)
    local d = {
        detail = detail,
        title = detail.title or _("Untitled"),
        author = table.concat(authors, ", "),
        cover_path = catalog:cachedThumbnailPath(detail),
        read_path = read_path,
        on_device = read_path ~= nil,
        supported = supported,
        file = file,
        about = description and (description:match("^[^\n]+") or description) or nil,
        chips = DetailData.chips(detail),
        status = status,
        status_label = DetailData.statusLabel(status),
        pct = (status == "reading" or status == "rereading") and pct and pct > 0 and pct or nil,
        allow_select = opts.allow_select == true,
        selected = opts.allow_select and catalog.bulkIsBookSelected and catalog:bulkIsBookSelected(detail) or false,
    }
    if file and not read_path then
        local folder = catalog:getLocalDownloadPreview(CatalogUtil.safeFilenameBase(detail), string.lower(file.format or "bin"), file.devicePath, false)
        local size = CatalogUtil.formatBytes(catalog:fileDisplaySize(file))
        d.file_note = T(_("%1, to %2"), catalog:fileFormatLabel(file) .. (size ~= "" and (", " .. size) or ""), BookPeek.folderLabel(folder) or folder)
    end
    return d
end

local function body(page, w)
    local d = page.peek
    local chips = {}
    if d.pct then
        table.insert(chips, MenuUI.chip(T(_("%1 · %2%"), d.status_label, math.floor(d.pct + 0.5)), { icon = "book-open" }))
    elseif d.status ~= "unread" then
        table.insert(chips, MenuUI.chip(d.status_label, { icon = d.status == "read" and "book-check" or "bookmark" }))
    end
    table.insert(chips, d.on_device and MenuUI.chip(_("On this device"), { icon = "bo-device" }) or MenuUI.chip(_("Not on this device"), { icon = "cloud" }))
    local items = {
        DialogUI.bookHead(w, { title = d.title, author = d.author }, { cover_path = d.cover_path, chips = chips }),
    }
    local pills = {}
    if d.on_device then
        table.insert(pills, { label = _("Read"), icon = "book-open", action = { kind = "read" } })
    elseif d.file then
        table.insert(pills, { label = _("Download"), icon = "download", action = { kind = "download" } })
    end
    table.insert(pills, { label = _("Details"), icon = "book-open-text", kind = "outline", action = { kind = "details" } })
    table.insert(items, DialogUI.pillRow(w, pills))
    if d.file_note then
        table.insert(items, DialogUI.note(w, "file-text", d.file_note, { col = INK.g4, data = true, lines = 1 }))
    end
    local iw = MenuUI.rowsIn(w)
    local rows = {}
    if d.about then
        table.insert(rows, MenuUI.row(iw, { icon = "file-text", label = _("About this book"), sub = d.about, sub_data = true, chevron = true, action = { kind = "about" } }))
    end
    if #d.chips > 0 then
        table.insert(rows, MenuUI.row(iw, { icon = "tag", label = _("Genres & tags"), sub = table.concat(d.chips, ", "), sub_data = true, chevron = true, action = { kind = "tags" } }))
    end
    if d.on_device then
        table.insert(rows, MenuUI.row(iw, { icon = "trash", label = _("Remove from this device"), sub = _("Stays in your library"), chevron = true, action = { kind = "remove" } }))
    elseif #d.supported > 0 then
        table.insert(rows, MenuUI.row(iw, { icon = "folder-open", label = _("Download options"), sub = _("Edition, folder and file name"), chevron = true, action = { kind = "download-options" } }))
    end
    if d.allow_select then
        table.insert(rows, MenuUI.row(iw, { icon = "list-checks", label = d.selected and _("Unselect") or _("Select"), sub = _("Pick books to download or mark read together"), chevron = true, action = { kind = "select" } }))
    end
    if #rows > 0 then table.insert(items, MenuUI.group(w, rows)) end
    return items
end

local function build(page, sw, sh)
    return DialogUI.sheet(page, sw, sh, function(w) return body(page, w) end, { pop_w = 460 })
end

local function onAction(page, action)
    local catalog, d = page.catalog, page.peek
    local detail = d.detail
    local kind = action.kind
    page:close()
    -- The sheet's backdrop is restored first, so the next page or sheet
    -- copies a clean screen.
    UIManager:tickAfterNext(function()
        if kind == "read" then
            catalog:openDownloadedFile(d.read_path)
        elseif kind == "download" then
            catalog:downloadDefaultFile(detail, d.file)
        elseif kind == "details" then
            catalog:showBookDetail(detail)
        elseif kind == "about" then
            catalog:showFullText(_("About this book"), detail.description, detail)
        elseif kind == "tags" then
            catalog:showGenresAndTags(detail)
        elseif kind == "download-options" then
            catalog:showDownloadOptions(detail)
        elseif kind == "remove" then
            BookPeek.remove(catalog, d.read_path)
        elseif kind == "select" then
            if catalog:isBulkSelectionActive() then
                catalog:bulkToggleBook(detail)
            else
                catalog:bulkEnterSelectionMode({ kind = "book", book = detail })
            end
        end
    end)
    return true
end

-- Deletes the file and its sidecar through KOReader's file manager, which
-- asks first. The book stays in the library.
function BookPeek.remove(catalog, path)
    local fm = require("apps/filemanager/filemanager").instance
    if not fm or not fm.showDeleteFileDialog then
        require("bookorbit_toast").error(_("Open the file browser to remove this book."))
        return
    end
    fm:showDeleteFileDialog(path, function()
        catalog:refreshOnDevice()
        catalog:markStackDirty()
        catalog:updateItems(nil, true)
    end)
end

function BookPeek.open(catalog, detail, opts)
    return DialogUI.open{
        name = "bookorbit_book_peek",
        build = build,
        on_action = onAction,
        catalog = catalog,
        peek = BookPeek.data(catalog, detail, opts),
    }
end

return BookPeek