You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koreader/frontend/apps/filemanager/filemanagerutil.lua

288 lines
10 KiB
Lua

--[[--
This module contains miscellaneous helper functions for FileManager
]]
local BD = require("ui/bidi")
local Device = require("device")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local ffiutil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
local T = ffiutil.template
local filemanagerutil = {}
function filemanagerutil.getDefaultDir()
return Device.home_dir or "."
end
function filemanagerutil.abbreviate(path)
if not path then return "" end
if G_reader_settings:nilOrTrue("shorten_home_dir") then
local home_dir = G_reader_settings:readSetting("home_dir") or filemanagerutil.getDefaultDir()
if path == home_dir or path == home_dir .. "/" then
return _("Home")
end
local len = home_dir:len()
local start = path:sub(1, len)
if start == home_dir and path:sub(len+1, len+1) == "/" then
return path:sub(len+2)
end
end
return path
end
function filemanagerutil.splitFileNameType(filepath)
local _, filename = util.splitFilePathName(filepath)
local filename_without_suffix, filetype = util.splitFileNameSuffix(filename)
filetype = filetype:lower()
if filetype == "zip" then
local filename_without_sub_suffix, sub_filetype = util.splitFileNameSuffix(filename_without_suffix)
sub_filetype = sub_filetype:lower()
local supported_sub_filetypes = { "fb2", "htm", "html", "log", "md", "rtf", "txt", }
if util.arrayContains(supported_sub_filetypes, sub_filetype) then
return filename_without_sub_suffix, sub_filetype .. ".zip"
end
end
return filename_without_suffix, filetype
end
-- Purge doc settings in sidecar directory
function filemanagerutil.purgeSettings(file)
local file_abs_path = ffiutil.realpath(file)
if file_abs_path then
return DocSettings:open(file_abs_path):purge()
end
end
-- Purge doc settings except kept
function filemanagerutil.resetDocumentSettings(file)
local settings_to_keep = {
bookmarks = true,
bookmarks_sorted_20220106 = true,
bookmarks_version = true,
cre_dom_version = true,
highlight = true,
highlights_imported = true,
last_page = true,
last_xpointer = true,
}
local file_abs_path = ffiutil.realpath(file)
if file_abs_path then
local doc_settings = DocSettings:open(file_abs_path)
for k in pairs(doc_settings.data) do
if not settings_to_keep[k] then
doc_settings:delSetting(k)
end
end
doc_settings:makeTrue("docsettings_reset_done") -- for readertypeset block_rendering_mode
doc_settings:flush()
end
end
-- Get a document status ("new", "reading", "complete", or "abandoned")
function filemanagerutil.getStatus(file)
if DocSettings:hasSidecarFile(file) then
local summary = DocSettings:open(file):readSetting("summary")
if summary and summary.status and summary.status ~= "" then
return summary.status
end
return "reading"
end
return "new"
end
-- Set a document status ("reading", "complete", or "abandoned")
function filemanagerutil.setStatus(file, status)
-- In case the book doesn't have a sidecar file, this'll create it
local doc_settings = DocSettings:open(file)
local summary = doc_settings:readSetting("summary") or {}
summary.status = status
summary.modified = os.date("%Y-%m-%d", os.time())
doc_settings:saveSetting("summary", summary)
doc_settings:flush()
end
function filemanagerutil.statusToString(status)
local status_to_text = {
new = _("Unread"),
reading = _("Reading"),
abandoned = _("On hold"),
complete = _("Finished"),
}
return status_to_text[status]
end
-- Generate all book status file dialog buttons in a row
function filemanagerutil.genStatusButtonsRow(file, caller_callback, current_status)
local status = current_status or filemanagerutil.getStatus(file)
local function genStatusButton(to_status)
return {
text = filemanagerutil.statusToString(to_status) .. (status == to_status and "" or ""),
id = to_status, -- used by covermenu
enabled = status ~= to_status,
callback = function()
filemanagerutil.setStatus(file, to_status)
caller_callback()
end,
}
end
return {
genStatusButton("reading"),
genStatusButton("abandoned"),
genStatusButton("complete"),
}
end
-- Generate "Reset" file dialog button
function filemanagerutil.genResetSettingsButton(file, caller_callback, button_disabled)
return {
text = _("Reset"),
id = "reset", -- used by covermenu
enabled = (not button_disabled and DocSettings:hasSidecarFile(ffiutil.realpath(file))) and true or false,
callback = function()
local ConfirmBox = require("ui/widget/confirmbox")
local confirmbox = ConfirmBox:new{
text = T(_("Reset this document?") .. "\n\n%1\n\n" ..
_("Document progress, settings, bookmarks, highlights, notes and custom cover image will be permanently lost."),
BD.filepath(file)),
ok_text = _("Reset"),
ok_callback = function()
local custom_metadata_purged = filemanagerutil.purgeSettings(file)
if custom_metadata_purged then -- refresh coverbrowser cached book info
local FileManager = require("apps/filemanager/filemanager")
local ui = FileManager.instance
if not ui then
local ReaderUI = require("apps/reader/readerui")
ui = ReaderUI.instance
end
if ui and ui.coverbrowser then
ui.coverbrowser:deleteBookInfo(file)
end
end
require("readhistory"):fileSettingsPurged(file)
caller_callback()
end,
}
UIManager:show(confirmbox)
end,
}
end
function filemanagerutil.genAddRemoveFavoritesButton(file, caller_callback, button_disabled)
local ReadCollection = require("readcollection")
local is_added = ReadCollection:checkItemExist(file)
return {
text_func = function()
return is_added and _("Remove from favorites") or _("Add to favorites")
end,
enabled = not button_disabled,
callback = function()
caller_callback()
if is_added then
ReadCollection:removeItem(file)
else
ReadCollection:addItem(file)
end
end,
}
end
function filemanagerutil.genShowFolderButton(file, caller_callback, button_disabled)
return {
text = _("Show folder"),
enabled = not button_disabled,
callback = function()
caller_callback()
local ui = require("apps/filemanager/filemanager").instance
if ui then
local pathname = util.splitFilePathName(file)
ui.file_chooser:changeToPath(pathname, file)
else
ui = require("apps/reader/readerui").instance
ui:onClose()
ui:showFileManager(file)
end
end,
}
end
function filemanagerutil.genBookInformationButton(file, caller_callback, button_disabled)
return {
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = not button_disabled,
callback = function()
caller_callback()
require("apps/filemanager/filemanagerbookinfo"):show(file)
end,
}
end
function filemanagerutil.genBookCoverButton(file, caller_callback, button_disabled)
return {
text = _("Book cover"),
id = "book_cover", -- used by covermenu
enabled = not button_disabled,
callback = function()
caller_callback()
require("apps/filemanager/filemanagerbookinfo"):onShowBookCover(file)
end,
}
end
function filemanagerutil.genBookDescriptionButton(file, caller_callback, button_disabled)
return {
text = _("Book description"),
id = "book_description", -- used by covermenu
enabled = not button_disabled,
callback = function()
caller_callback()
require("apps/filemanager/filemanagerbookinfo"):onShowBookDescription(nil, file)
end,
}
end
-- Generate "Execute script" file dialog button
function filemanagerutil.genExecuteScriptButton(file, caller_callback)
local InfoMessage = require("ui/widget/infomessage")
return {
-- @translators This is the script's programming language (e.g., shell or python)
text = T(_("Execute %1 script"), util.getScriptType(file)),
callback = function()
caller_callback()
local script_is_running_msg = InfoMessage:new{
-- @translators %1 is the script's programming language (e.g., shell or python), %2 is the filename
text = T(_("Running %1 script %2…"), util.getScriptType(file), BD.filename(ffiutil.basename(file))),
}
UIManager:show(script_is_running_msg)
UIManager:scheduleIn(0.5, function()
local rv
if Device:isAndroid() then
Device:setIgnoreInput(true)
rv = os.execute("sh " .. ffiutil.realpath(file)) -- run by sh, because sdcard has no execute permissions
Device:setIgnoreInput(false)
else
rv = os.execute(ffiutil.realpath(file))
end
UIManager:close(script_is_running_msg)
if rv == 0 then
UIManager:show(InfoMessage:new{
text = _("The script exited successfully."),
})
else
--- @note: Lua 5.1 returns the raw return value from the os's system call. Counteract this madness.
UIManager:show(InfoMessage:new{
text = T(_("The script returned a non-zero status code: %1!"), bit.rshift(rv, 8)),
icon = "notice-warning",
})
end
end)
end,
}
end
return filemanagerutil