DocSettings: add support of centralized sdr storage (#10132)

reviewable/pr10135/r1
hius07 1 year ago committed by GitHub
parent e55b60175b
commit 15605291c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -182,13 +182,6 @@ function FileManager:setupLayout()
return true
end
local copyFile = function(file) self:copyFile(file) end
local pasteHere = function(file) self:pasteHere(file) end
local cutFile = function(file) self:cutFile(file) end
local deleteFile = function(file) self:deleteFile(file) end
local renameFile = function(file) self:renameFile(file) end
local setHome = function(path) self:setHome(path) end
function file_chooser:onFileHold(file)
if file_manager.select_mode then
file_manager:tapPlus()
@ -207,16 +200,16 @@ function FileManager:setupLayout()
text = C_("File", "Copy"),
enabled = is_not_parent_folder,
callback = function()
copyFile(file)
UIManager:close(self.file_dialog)
file_manager:copyFile(file)
end,
},
{
text = C_("File", "Paste"),
enabled = file_manager.clipboard and true or false,
callback = function()
pasteHere(file)
UIManager:close(self.file_dialog)
file_manager:pasteHere(file)
end,
},
{
@ -236,8 +229,8 @@ function FileManager:setupLayout()
text = _("Cut"),
enabled = is_not_parent_folder,
callback = function()
cutFile(file)
UIManager:close(self.file_dialog)
file_manager:cutFile(file)
end,
},
{
@ -245,16 +238,10 @@ function FileManager:setupLayout()
enabled = is_not_parent_folder,
callback = function()
UIManager:close(self.file_dialog)
UIManager:show(ConfirmBox:new{
text = is_file and T(_("Delete file?\n\n%1\n\nIf you delete a file, it is permanently lost."), BD.filepath(file)) or
T(_("Delete folder?\n\n%1\n\nIf you delete a folder, its content is permanently lost."), BD.filepath(file)),
ok_text = _("Delete"),
ok_callback = function()
deleteFile(file)
require("readhistory"):fileDeleted(file)
self:refreshPath()
end,
})
local function post_delete_callback()
self:refreshPath()
end
file_manager:showDeleteFileDialog(file, post_delete_callback)
end,
},
{
@ -262,123 +249,54 @@ function FileManager:setupLayout()
enabled = is_not_parent_folder,
callback = function()
UIManager:close(self.file_dialog)
file_manager.rename_dialog = InputDialog:new{
title = is_file and _("Rename file") or _("Rename folder"),
input = BaseUtil.basename(file),
buttons = {{
{
text = _("Cancel"),
id = "close",
enabled = true,
callback = function()
UIManager:close(file_manager.rename_dialog)
end,
},
{
text = _("Rename"),
enabled = true,
callback = function()
if file_manager.rename_dialog:getInputText() ~= "" then
renameFile(file)
UIManager:close(file_manager.rename_dialog)
end
end,
},
}},
}
UIManager:show(file_manager.rename_dialog)
file_manager.rename_dialog:onShowKeyboard()
file_manager:showRenameFileDialog(file, is_file)
end,
}
},
-- a little hack to get visual functionality grouping
{
},
{}, -- separator
}
if is_file and Device:canExecuteScript(file) then
-- NOTE: We populate the empty separator, in order not to mess with the button reordering code in CoverMenu
table.insert(buttons[3],
{
-- @translators This is the script's programming language (e.g., shell or python)
text = T(_("Execute %1 script"), util.getScriptType(file)),
enabled = true,
callback = function()
UIManager:close(self.file_dialog)
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(BaseUtil.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 " .. BaseUtil.realpath(file)) -- run by sh, because sdcard has no execute permissions
Device:setIgnoreInput(false)
else
rv = os.execute(BaseUtil.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,
}
)
table.insert(buttons, {}) -- separator
end
if is_file then
local function status_button_callback()
self:refreshPath()
UIManager:close(self.file_dialog)
self:refreshPath() -- sidecar folder may be created/deleted
end
local has_provider = DocumentRegistry:getProviders(file) ~= nil
if has_provider or DocSettings:hasSidecarFile(file) then
table.insert(buttons, filemanagerutil.genStatusButtonsRow(file, status_button_callback))
table.insert(buttons, {}) -- separator
end
table.insert(buttons, filemanagerutil.genStatusButtonsRow(file, status_button_callback))
table.insert(buttons, {}) -- separator
table.insert(buttons, {
filemanagerutil.genResetSettingsButton(file, nil, status_button_callback),
filemanagerutil.genResetSettingsButton(file, status_button_callback),
{
text_func = function()
if ReadCollection:checkItemExist(file) then
return _("Remove from favorites")
else
return _("Add to favorites")
end
return ReadCollection:checkItemExist(file)
and _("Remove from favorites") or _("Add to favorites")
end,
enabled = DocumentRegistry:getProviders(file) ~= nil,
enabled = has_provider,
callback = function()
UIManager:close(self.file_dialog)
if ReadCollection:checkItemExist(file) then
ReadCollection:removeItem(file)
else
ReadCollection:addItem(file)
end
UIManager:close(self.file_dialog)
end,
},
})
table.insert(buttons, {
{
text = _("Open with…"),
enabled = DocumentRegistry:getProviders(file) == nil or #(DocumentRegistry:getProviders(file)) > 1 or file_manager.texteditor,
callback = function()
UIManager:close(self.file_dialog)
local one_time_providers = {}
table.insert(one_time_providers, {
provider_name = _("Text viewer"),
callback = function()
file_manager:openTextViewer(file)
end,
})
local one_time_providers = {
{
provider_name = _("Text viewer"),
callback = function()
file_manager:openTextViewer(file)
end,
},
}
if file_manager.texteditor then
table.insert(one_time_providers, {
provider_name = _("Text editor"),
@ -393,18 +311,24 @@ function FileManager:setupLayout()
{
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = FileManagerBookInfo:isSupported(file),
callback = function()
FileManagerBookInfo:show(file)
UIManager:close(self.file_dialog)
FileManagerBookInfo:show(file)
end,
}
})
if Device:canExecuteScript(file) then
local function button_callback()
UIManager:close(self.file_dialog)
end
table.insert(buttons, {
filemanagerutil.genExecuteScriptButton(file, button_callback)
})
end
if FileManagerConverter:isSupported(file) then
table.insert(buttons, {
{
text = _("Convert"),
enabled = true,
callback = function()
UIManager:close(self.file_dialog)
FileManagerConverter:showConvertButtons(file, self)
@ -413,28 +337,21 @@ function FileManager:setupLayout()
})
end
end
if is_folder then
local realpath = BaseUtil.realpath(file)
table.insert(buttons, {
{
text = _("Set as HOME folder"),
callback = function()
setHome(realpath)
UIManager:close(self.file_dialog)
file_manager:setHome(BaseUtil.realpath(file))
end
}
})
end
local title
if is_folder then
title = BD.directory(file:match("([^/]+)$"))
else
title = BD.filename(file:match("([^/]+)$"))
end
self.file_dialog = ButtonDialogTitle:new{
title = title,
title = is_file and BD.filename(file:match("([^/]+)$")) or BD.directory(file:match("([^/]+)$")),
title_align = "center",
buttons = buttons,
}
@ -607,9 +524,9 @@ function FileManager:tapPlus()
{
text = _("Select all files in folder"),
callback = function()
UIManager:close(self.file_dialog)
self.file_chooser:selectAllFilesInFolder()
self:onRefresh()
UIManager:close(self.file_dialog)
end,
},
{
@ -620,13 +537,13 @@ function FileManager:tapPlus()
text = _("Copy selected files to the current folder?"),
ok_text = _("Copy"),
ok_callback = function()
UIManager:close(self.file_dialog)
self.cutfile = false
for file in pairs(self.selected_files) do
self.clipboard = file
self:pasteHere(self.file_chooser.path)
end
self:onToggleSelectMode()
UIManager:close(self.file_dialog)
end,
})
end
@ -637,9 +554,9 @@ function FileManager:tapPlus()
text = _("Deselect all"),
enabled = actions_enabled,
callback = function()
UIManager:close(self.file_dialog)
self.selected_files = {}
self:onRefresh()
UIManager:close(self.file_dialog)
end,
},
{
@ -650,13 +567,13 @@ function FileManager:tapPlus()
text = _("Move selected files to the current folder?"),
ok_text = _("Move"),
ok_callback = function()
UIManager:close(self.file_dialog)
self.cutfile = true
for file in pairs(self.selected_files) do
self.clipboard = file
self:pasteHere(self.file_chooser.path)
end
self:onToggleSelectMode()
UIManager:close(self.file_dialog)
end,
})
end
@ -666,8 +583,8 @@ function FileManager:tapPlus()
{
text = _("Exit select mode"),
callback = function()
self:onToggleSelectMode()
UIManager:close(self.file_dialog)
self:onToggleSelectMode()
end,
},
{
@ -678,19 +595,17 @@ function FileManager:tapPlus()
text = _("Delete selected files?\nIf you delete a file, it is permanently lost."),
ok_text = _("Delete"),
ok_callback = function()
local readhistory = require("readhistory")
UIManager:close(self.file_dialog)
for file in pairs(self.selected_files) do
self:deleteFile(file)
readhistory:fileDeleted(file)
self:deleteFile(file, true) -- only files can be selected
end
self:onToggleSelectMode()
UIManager:close(self.file_dialog)
end,
})
end
},
},
{},
{}, -- separator
{
{
text = _("New folder"),
@ -715,8 +630,8 @@ function FileManager:tapPlus()
{
text = _("Select files"),
callback = function()
self:onToggleSelectMode(true) -- no full screen refresh
UIManager:close(self.file_dialog)
self:onToggleSelectMode(true) -- no full screen refresh
end,
},
},
@ -734,9 +649,8 @@ function FileManager:tapPlus()
text = _("Paste"),
enabled = self.clipboard and true or false,
callback = function()
self:pasteHere(self.file_chooser.path)
self:onRefresh()
UIManager:close(self.file_dialog)
self:pasteHere(self.file_chooser.path)
end,
},
},
@ -744,8 +658,8 @@ function FileManager:tapPlus()
{
text = _("Set as HOME folder"),
callback = function()
self:setHome(self.file_chooser.path)
UIManager:close(self.file_dialog)
self:setHome(self.file_chooser.path)
end
}
},
@ -753,8 +667,8 @@ function FileManager:tapPlus()
{
text = _("Go to HOME folder"),
callback = function()
self:goHome()
UIManager:close(self.file_dialog)
self:goHome()
end
}
},
@ -762,8 +676,8 @@ function FileManager:tapPlus()
{
text = _("Open random document"),
callback = function()
self:openRandomFile(self.file_chooser.path)
UIManager:close(self.file_dialog)
self:openRandomFile(self.file_chooser.path)
end
}
},
@ -771,52 +685,47 @@ function FileManager:tapPlus()
{
text = _("Folder shortcuts"),
callback = function()
self:handleEvent(Event:new("ShowFolderShortcutsDialog"))
UIManager:close(self.file_dialog)
self:handleEvent(Event:new("ShowFolderShortcutsDialog"))
end
}
}
}
if Device:canImportFiles() then
table.insert(buttons, 4, {
{
text = _("Import files here"),
enabled = Device:isValidPath(self.file_chooser.path),
callback = function()
local current_dir = self.file_chooser.path
UIManager:close(self.file_dialog)
Device.importFile(current_dir)
end,
},
})
end
if Device:hasExternalSD() then
table.insert(buttons, 5, {
table.insert(buttons, 4, { -- after "Paste" or "Import files here" button
{
text_func = function()
if Device:isValidPath(self.file_chooser.path) then
return _("Switch to SDCard")
else
return _("Switch to internal storage")
end
return Device:isValidPath(self.file_chooser.path)
and _("Switch to SDCard") or _("Switch to internal storage")
end,
callback = function()
UIManager:close(self.file_dialog)
if Device:isValidPath(self.file_chooser.path) then
local ok, sd_path = Device:hasExternalSD()
UIManager:close(self.file_dialog)
if ok then
self.file_chooser:changeToPath(sd_path)
end
else
UIManager:close(self.file_dialog)
self.file_chooser:changeToPath(Device.home_dir)
end
end,
},
})
end
if Device:canImportFiles() then
table.insert(buttons, 4, { -- always after "Paste" button
{
text = _("Import files here"),
enabled = Device:isValidPath(self.file_chooser.path),
callback = function()
UIManager:close(self.file_dialog)
Device.importFile(self.file_chooser.path)
end,
},
})
end
end
self.file_dialog = ButtonDialogTitle:new{
@ -853,9 +762,7 @@ function FileManager:reinit(path, focused_file)
end
function FileManager:getCurrentDir()
if FileManager.instance then
return FileManager.instance.file_chooser.path
end
return FileManager.instance and FileManager.instance.file_chooser.path
end
function FileManager:toggleHiddenFiles()
@ -970,75 +877,64 @@ function FileManager:cutFile(file)
end
function FileManager:pasteHere(file)
if self.clipboard then
file = BaseUtil.realpath(file)
local orig_basename = BaseUtil.basename(self.clipboard)
local orig = BaseUtil.realpath(self.clipboard)
local dest = lfs.attributes(file, "mode") == "directory" and
file or file:match("(.*/)")
local function infoCopyFile()
-- if we copy a file, also copy its sidecar directory
if DocSettings:hasSidecarFile(orig) then
BaseUtil.execute(self.cp_bin, "-r", DocSettings:getSidecarDir(orig), dest)
end
if BaseUtil.execute(self.cp_bin, "-r", orig, dest) ~= 0 then
UIManager:show(InfoMessage:new {
text = T(_("Failed to copy:\n%1\nto:\n%2"), BD.filepath(orig_basename), BD.dirpath(dest)),
icon = "notice-warning",
})
local orig_file = BaseUtil.realpath(self.clipboard)
local orig_name = BaseUtil.basename(self.clipboard)
local dest_path = BaseUtil.realpath(file)
dest_path = lfs.attributes(dest_path, "mode") == "directory" and dest_path or dest_path:match("(.*/)")
local dest_file = BaseUtil.joinPath(dest_path, orig_name)
local is_file = lfs.attributes(orig_file, "mode") == "file"
local function infoCopyFile()
if self:copyRecursive(orig_file, dest_path) then
if is_file then
DocSettings:update(orig_file, dest_file, true)
end
return true
else
UIManager:show(InfoMessage:new {
text = T(_("Failed to copy:\n%1\nto:\n%2"), BD.filepath(orig_name), BD.dirpath(dest_path)),
icon = "notice-warning",
})
end
end
local function infoMoveFile()
-- if we move a file, also move its sidecar directory
if DocSettings:hasSidecarFile(orig) then
self:moveFile(DocSettings:getSidecarDir(orig), dest) -- dest is always a directory
end
if self:moveFile(orig, dest) then
-- Update history and collections.
local dest_file = string.format("%s/%s", dest, BaseUtil.basename(orig))
require("readhistory"):updateItemByPath(orig, dest_file) -- (will update "lastfile" if needed)
ReadCollection:updateItemByPath(orig, dest_file)
else
UIManager:show(InfoMessage:new {
text = T(_("Failed to move:\n%1\nto:\n%2"), BD.filepath(orig_basename), BD.dirpath(dest)),
icon = "notice-warning",
})
local function infoMoveFile()
if self:moveFile(orig_file, dest_path) then
if is_file then
DocSettings:update(orig_file, dest_file)
require("readhistory"):updateItemByPath(orig_file, dest_file) -- (will update "lastfile" if needed)
end
end
local info_file
if self.cutfile then
info_file = infoMoveFile
ReadCollection:updateItemByPath(orig_file, dest_file)
return true
else
info_file = infoCopyFile
UIManager:show(InfoMessage:new {
text = T(_("Failed to move:\n%1\nto:\n%2"), BD.filepath(orig_name), BD.dirpath(dest_path)),
icon = "notice-warning",
})
end
local basename = BaseUtil.basename(self.clipboard)
local mode = lfs.attributes(string.format("%s/%s", dest, basename), "mode")
if mode == "file" or mode == "directory" then
local text
if mode == "file" then
text = T(_("File already exists:\n%1\nOverwrite file?"), BD.filename(basename))
else
text = T(_("Folder already exists:\n%1\nOverwrite folder?"), BD.directory(basename))
end
end
UIManager:show(ConfirmBox:new {
text = text,
ok_text = _("Overwrite"),
ok_callback = function()
info_file()
self:onRefresh()
self.clipboard = nil
end,
})
else
info_file()
local function doPaste()
local ok = self.cutfile and infoMoveFile() or infoCopyFile()
if ok then
self:onRefresh()
self.clipboard = nil
end
end
local mode = lfs.attributes(dest_file, "mode")
if mode then
UIManager:show(ConfirmBox:new {
text = mode == "file" and T(_("File already exists:\n%1\nOverwrite file?"), BD.filename(orig_name))
or T(_("Folder already exists:\n%1\nOverwrite folder?"), BD.directory(orig_name)),
ok_text = _("Overwrite"),
ok_callback = function()
doPaste()
end,
})
else
doPaste()
end
end
function FileManager:createFolder()
@ -1062,7 +958,7 @@ function FileManager:createFolder()
if new_folder_name == "" then return end
UIManager:close(input_dialog)
local new_folder = string.format("%s/%s", self.file_chooser.path, new_folder_name)
if BaseUtil.execute(self.mkdir_bin, new_folder) == 0 then
if util.makePath(new_folder) then
if check_button_enter_folder.checked then
self.file_chooser:changeToPath(new_folder)
else
@ -1089,8 +985,28 @@ function FileManager:createFolder()
input_dialog:onShowKeyboard()
end
function FileManager:deleteFile(file)
local ok, err, is_dir
function FileManager:showDeleteFileDialog(file, post_delete_callback, pre_delete_callback)
local file_abs_path = BaseUtil.realpath(file)
local is_file = lfs.attributes(file_abs_path, "mode") == "file"
local text = (is_file and _("Delete file permanently?") or _("Delete folder permanently?")) .. "\n\n" .. BD.filepath(file)
if is_file and DocSettings:hasSidecarFile(file_abs_path) then
text = text .. "\n\n" .. _("Book settings, highlights and notes will be deleted.")
end
UIManager:show(ConfirmBox:new{
text = text,
ok_text = _("Delete"),
ok_callback = function()
if pre_delete_callback then
pre_delete_callback()
end
if self:deleteFile(file, is_file) and post_delete_callback then
post_delete_callback()
end
end,
})
end
function FileManager:deleteFile(file, is_file)
local file_abs_path = BaseUtil.realpath(file)
if file_abs_path == nil then
UIManager:show(InfoMessage:new{
@ -1100,24 +1016,19 @@ function FileManager:deleteFile(file)
return
end
local is_doc = DocumentRegistry:hasProvider(file_abs_path)
if lfs.attributes(file_abs_path, "mode") == "file" then
local ok, err
if is_file then
ok, err = os.remove(file_abs_path)
else
ok, err = BaseUtil.purgeDir(file_abs_path)
is_dir = true
end
if ok and not err then
if is_doc then
local doc_settings = DocSettings:open(file)
-- remove cache if any
local cache_file_path = doc_settings:readSetting("cache_file_path")
if cache_file_path then
os.remove(cache_file_path)
end
doc_settings:purge()
if is_file then
DocSettings:update(file)
require("readhistory"):fileDeleted(file)
end
ReadCollection:removeItemByPath(file, is_dir)
ReadCollection:removeItemByPath(file, not is_file)
return true
else
UIManager:show(InfoMessage:new{
text = T(_("Failed to delete:\n%1"), BD.filepath(file)),
@ -1126,76 +1037,86 @@ function FileManager:deleteFile(file)
end
end
function FileManager:renameFile(file)
local basename = self.rename_dialog:getInputText()
if BaseUtil.basename(file) ~= basename then
local dest = BaseUtil.joinPath(BaseUtil.dirname(file), basename)
local function doRenameFile()
if self:moveFile(file, dest) then
require("readhistory"):updateItemByPath(file, dest) -- (will update "lastfile" if needed)
ReadCollection:updateItemByPath(file, dest)
if lfs.attributes(dest, "mode") == "file" then
local doc = require("docsettings")
local move_history = true
if lfs.attributes(doc:getHistoryPath(file), "mode") == "file" and
not self:moveFile(doc:getHistoryPath(file), doc:getHistoryPath(dest)) then
move_history = false
end
if lfs.attributes(doc:getSidecarDir(file), "mode") == "directory" and
not self:moveFile(doc:getSidecarDir(file), doc:getSidecarDir(dest)) then
move_history = false
end
if not move_history then
UIManager:show(InfoMessage:new{
text = T(_("Renamed file:\n%1\nto:\n%2\n\nFailed to move history data.\nThe reading history may be lost."),
BD.filepath(file), BD.filepath(dest)),
icon = "notice-warning",
})
function FileManager:showRenameFileDialog(file, is_file)
local dialog
dialog = InputDialog:new{
title = is_file and _("Rename file") or _("Rename folder"),
input = BaseUtil.basename(file),
buttons = {{
{
text = _("Cancel"),
id = "close",
callback = function()
UIManager:close(dialog)
end,
},
{
text = _("Rename"),
callback = function()
local new_name = dialog:getInputText()
if new_name ~= "" then
UIManager:close(dialog)
self:renameFile(file, new_name, is_file)
end
end
else
UIManager:show(InfoMessage:new{
text = T(_("Failed to rename:\n%1\nto:\n%2"), BD.filepath(file), BD.filepath(dest)),
icon = "notice-warning",
})
end,
},
}},
}
UIManager:show(dialog)
dialog:onShowKeyboard()
end
function FileManager:renameFile(file, basename, is_file)
if BaseUtil.basename(file) == basename then return end
local dest = BaseUtil.joinPath(BaseUtil.dirname(file), basename)
local function doRenameFile()
if self:moveFile(file, dest) then
if is_file then
DocSettings:update(file, dest)
require("readhistory"):updateItemByPath(file, dest) -- (will update "lastfile" if needed)
end
ReadCollection:updateItemByPath(file, dest)
self:onRefresh()
else
UIManager:show(InfoMessage:new{
text = T(_("Failed to rename:\n%1\nto:\n%2"), BD.filepath(file), BD.filepath(dest)),
icon = "notice-warning",
})
end
end
local mode_dest = lfs.attributes(dest, "mode")
local mode_file = lfs.attributes(file, "mode")
if mode_dest then
local text, ok_text
if mode_dest ~= mode_file then
if mode_file == "file" then
text = T(_("Folder already exists:\n%1\nFile cannot be renamed."), BD.directory(basename))
else
text = T(_("File already exists:\n%1\nFolder cannot be renamed."), BD.filename(basename))
end
UIManager:show(InfoMessage:new {
text = text,
icon = "notice-warning",
})
local mode_dest = lfs.attributes(dest, "mode")
if mode_dest then
local text, ok_text
if (mode_dest == "file") ~= is_file then
if is_file then
text = T(_("Folder already exists:\n%1\nFile cannot be renamed."), BD.directory(basename))
else
if mode_file == "file" then
text = T(_("File already exists:\n%1\nOverwrite file?"), BD.filename(basename))
ok_text = _("Overwrite")
else
text = T(_("Folder already exists:\n%1\nMove the folder inside it?"), BD.directory(basename))
ok_text = _("Move")
end
UIManager:show(ConfirmBox:new {
text = text,
ok_text = ok_text,
ok_callback = function()
doRenameFile()
self:onRefresh()
end,
})
text = T(_("File already exists:\n%1\nFolder cannot be renamed."), BD.filename(basename))
end
UIManager:show(InfoMessage:new {
text = text,
icon = "notice-warning",
})
else
doRenameFile()
self:onRefresh()
if is_file then
text = T(_("File already exists:\n%1\nOverwrite file?"), BD.filename(basename))
ok_text = _("Overwrite")
else
text = T(_("Folder already exists:\n%1\nMove the folder inside it?"), BD.directory(basename))
ok_text = _("Move")
end
UIManager:show(ConfirmBox:new {
text = text,
ok_text = ok_text,
ok_callback = function()
doRenameFile()
end,
})
end
else
doRenameFile()
end
end

@ -1,18 +1,13 @@
local BD = require("ui/bidi")
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local Device = require("device")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local InfoMessage = require("ui/widget/infomessage")
local Menu = require("ui/widget/menu")
local ReadCollection = require("readcollection")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = require("device").screen
local filemanagerutil = require("apps/filemanager/filemanagerutil")
local BaseUtil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
local T = BaseUtil.template
local FileManagerCollection = WidgetContainer:extend{
coll_menu_title = _("Favorites"),
@ -42,97 +37,74 @@ function FileManagerCollection:updateItemTable()
end
function FileManagerCollection:onMenuHold(item)
local readerui_instance = require("apps/reader/readerui"):_getRunningInstance()
local currently_opened_file = readerui_instance and readerui_instance.document and readerui_instance.document.file
self.collfile_dialog = nil
local function status_button_callback()
self._manager:updateItemTable()
UIManager:close(self.collfile_dialog)
self._manager:updateItemTable()
end
local is_currently_opened = item.file == (self.ui.document and self.ui.document.file)
local buttons = {}
if not (item.dim or is_currently_opened) then
table.insert(buttons, filemanagerutil.genStatusButtonsRow(item.file, status_button_callback))
table.insert(buttons, {}) -- separator
end
local buttons = {
filemanagerutil.genStatusButtonsRow(item.file, status_button_callback),
{},
table.insert(buttons, {
filemanagerutil.genResetSettingsButton(item.file, status_button_callback, is_currently_opened),
{
filemanagerutil.genResetSettingsButton(item.file, currently_opened_file, status_button_callback),
{
text = _("Remove from collection"),
callback = function()
ReadCollection:removeItem(item.file, self._manager.coll_menu.collection)
self._manager:updateItemTable()
UIManager:close(self.collfile_dialog)
end,
},
text = _("Remove from favorites"),
callback = function()
UIManager:close(self.collfile_dialog)
ReadCollection:removeItem(item.file, self._manager.coll_menu.collection)
self._manager:updateItemTable()
end,
},
})
table.insert(buttons, {
{
{
text = _("Sort collection"),
callback = function()
UIManager:close(self.collfile_dialog)
local item_table = {}
for i=1, #self._manager.coll_menu.item_table do
table.insert(item_table, {text = self._manager.coll_menu.item_table[i].text, label = self._manager.coll_menu.item_table[i].file})
end
local SortWidget = require("ui/widget/sortwidget")
local sort_item
sort_item = SortWidget:new{
title = _("Sort favorites"),
item_table = item_table,
callback = function()
local new_order_table = {}
for i=1, #sort_item.item_table do
table.insert(new_order_table, {
file = sort_item.item_table[i].label,
order = i
})
end
ReadCollection:writeCollection(new_order_table, self._manager.coll_menu.collection)
self._manager:updateItemTable()
text = _("Sort favorites"),
callback = function()
UIManager:close(self.collfile_dialog)
local item_table = {}
for _, v in ipairs(self._manager.coll_menu.item_table) do
table.insert(item_table, {text = v.text, label = v.file})
end
local SortWidget = require("ui/widget/sortwidget")
local sort_item
sort_item = SortWidget:new{
title = _("Sort favorites"),
item_table = item_table,
callback = function()
local new_order_table = {}
for i, v in ipairs(sort_item.item_table) do
table.insert(new_order_table, {
file = v.label,
order = i,
})
end
}
UIManager:show(sort_item)
end,
},
{
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = FileManagerBookInfo:isSupported(item.file),
callback = function()
FileManagerBookInfo:show(item.file)
UIManager:close(self.collfile_dialog)
end,
},
ReadCollection:writeCollection(new_order_table, self._manager.coll_menu.collection)
self._manager:updateItemTable()
end
}
UIManager:show(sort_item)
end,
},
}
-- NOTE: Duplicated from frontend/apps/filemanager/filemanager.lua
{
text = _("Book information"),
id = "book_information", -- used by covermenu
callback = function()
UIManager:close(self.collfile_dialog)
FileManagerBookInfo:show(item.file)
end,
},
})
if Device:canExecuteScript(item.file) then
local function button_callback()
UIManager:close(self.collfile_dialog)
end
table.insert(buttons, {
{
-- @translators This is the script's programming language (e.g., shell or python)
text = T(_("Execute %1 script"), util.getScriptType(item.file)),
enabled = true,
callback = function()
UIManager:close(self.collfile_dialog)
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(item.file), BD.filename(BaseUtil.basename(item.file))),
}
UIManager:show(script_is_running_msg)
UIManager:scheduleIn(0.5, function()
local rv = os.execute(BaseUtil.realpath(item.file))
UIManager:close(script_is_running_msg)
if rv == 0 then
UIManager:show(InfoMessage:new{
text = _("The script exited successfully."),
})
else
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,
}
filemanagerutil.genExecuteScriptButton(item.file, button_callback)
})
end

@ -1,17 +1,15 @@
local BD = require("ui/bidi")
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local ConfirmBox = require("ui/widget/confirmbox")
local FFIUtil = require("ffi/util")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local Menu = require("ui/widget/menu")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = require("device").screen
local filemanagerutil = require("apps/filemanager/filemanagerutil")
local lfs = require("libs/libkoreader-lfs")
local _ = require("gettext")
local C_ = _.pgettext
local T = FFIUtil.template
local T = require("ffi/util").template
local FileManagerHistory = WidgetContainer:extend{
hist_menu_title = _("History"),
@ -31,7 +29,6 @@ function FileManagerHistory:init()
end
function FileManagerHistory:addToMainMenu(menu_items)
-- insert table to main tab of filemanager menu
menu_items.history = {
text = self.hist_menu_title,
callback = function()
@ -41,16 +38,13 @@ function FileManagerHistory:addToMainMenu(menu_items)
end
function FileManagerHistory:fetchStatuses(count)
local status
for _, v in ipairs(require("readhistory").hist) do
if v.dim then
status = "deleted"
else
status = filemanagerutil.getStatus(v.file)
v.status = v.dim and "deleted" or filemanagerutil.getStatus(v.file)
if v.status == "new" and v.file == (self.ui.document and self.ui.document.file) then
v.status = "reading" -- file currently opened for the first time
end
v.status = status
if count then
self.count[status] = self.count[status] + 1
self.count[v.status] = self.count[v.status] + 1
end
end
self.statuses_fetched = true
@ -85,64 +79,60 @@ function FileManagerHistory:onSetDimensions(dimen)
end
function FileManagerHistory:onMenuHold(item)
local readerui_instance = require("apps/reader/readerui"):_getRunningInstance()
local currently_opened_file = readerui_instance and readerui_instance.document and readerui_instance.document.file
self.histfile_dialog = nil
local function status_button_callback()
UIManager:close(self.histfile_dialog)
if self._manager.filter ~= "all" then
self._manager:fetchStatuses(false)
else
self._manager.statuses_fetched = false
end
self._manager:updateItemTable()
UIManager:close(self.histfile_dialog)
self._manager.files_updated = true -- sidecar folder may be created/deleted
end
local is_currently_opened = item.file == (self.ui.document and self.ui.document.file)
local buttons = {}
if not (item.dim or is_currently_opened) then
table.insert(buttons, filemanagerutil.genStatusButtonsRow(item.file, status_button_callback))
table.insert(buttons, {}) -- separator
end
local buttons = {
table.insert(buttons, {
filemanagerutil.genResetSettingsButton(item.file, status_button_callback, is_currently_opened),
{
filemanagerutil.genResetSettingsButton(item.file, currently_opened_file, status_button_callback),
{
text = _("Remove from history"),
callback = function()
require("readhistory"):removeItem(item)
self._manager:updateItemTable()
UIManager:close(self.histfile_dialog)
end,
},
text = _("Remove from history"),
callback = function()
UIManager:close(self.histfile_dialog)
require("readhistory"):removeItem(item)
self._manager:updateItemTable()
end,
},
})
table.insert(buttons, {
{
{
text = _("Delete"),
enabled = (item.file ~= currently_opened_file and lfs.attributes(item.file, "mode")) and true or false,
callback = function()
UIManager:show(ConfirmBox:new{
text = T(_("Are you sure that you want to delete this document?\n\n%1\n\nIf you delete a file, it is permanently lost."),
BD.filepath(item.file)),
ok_text = _("Delete"),
ok_callback = function()
local FileManager = require("apps/filemanager/filemanager")
FileManager:deleteFile(item.file)
require("readhistory"):fileDeleted(item.file) -- (will update "lastfile" if needed)
self._manager:updateItemTable()
UIManager:close(self.histfile_dialog)
end,
})
end,
},
{
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = FileManagerBookInfo:isSupported(item.file),
callback = function()
FileManagerBookInfo:show(item.file)
text = _("Delete"),
enabled = not (item.dim or is_currently_opened),
callback = function()
local function post_delete_callback()
UIManager:close(self.histfile_dialog)
end,
},
self._manager:updateItemTable()
self._manager.files_updated = true
end
local FileManager = require("apps/filemanager/filemanager")
FileManager:showDeleteFileDialog(item.file, post_delete_callback)
end,
},
}
if not item.dim then
table.insert(buttons, 1, filemanagerutil.genStatusButtonsRow(item.file, status_button_callback))
table.insert(buttons, 2, {})
end
{
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = not item.dim,
callback = function()
UIManager:close(self.histfile_dialog)
FileManagerBookInfo:show(item.file)
end,
},
})
self.histfile_dialog = ButtonDialogTitle:new{
title = BD.filename(item.text:match("([^/]+)$")),
title_align = "center",
@ -190,6 +180,13 @@ function FileManagerHistory:onShowHist()
end
self:updateItemTable()
self.hist_menu.close_callback = function()
if self.files_updated then -- refresh Filemanager list of files
local FileManager = require("apps/filemanager/filemanager")
if FileManager.instance then
FileManager.instance:onRefresh()
end
self.files_updated = nil
end
self.statuses_fetched = nil
UIManager:close(self.hist_menu)
G_reader_settings:saveSetting("history_filter", self.filter)
@ -218,17 +215,15 @@ function FileManagerHistory:showHistDialog()
table.insert(buttons, {
genFilterButton("reading"),
genFilterButton("abandoned"),
})
table.insert(buttons, {
genFilterButton("complete"),
genFilterButton("deleted"),
})
table.insert(buttons, {
genFilterButton("all"),
genFilterButton("new"),
genFilterButton("deleted"),
})
if self.count.deleted > 0 then
table.insert(buttons, {})
table.insert(buttons, {}) -- separator
table.insert(buttons, {
{
text = _("Clear history of deleted files"),
@ -243,7 +238,7 @@ function FileManagerHistory:showHistDialog()
end,
})
end,
},
},
})
end
hist_dialog = ButtonDialogTitle:new{

@ -6,10 +6,12 @@ local BD = require("ui/bidi")
local ConfirmBox = require("ui/widget/confirmbox")
local Device = require("device")
local DocSettings = require("docsettings")
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local util = require("ffi/util")
local ffiutil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
local T = util.template
local T = ffiutil.template
local filemanagerutil = {}
@ -35,7 +37,7 @@ end
-- Purge doc settings in sidecar directory
function filemanagerutil.purgeSettings(file)
local file_abs_path = util.realpath(file)
local file_abs_path = ffiutil.realpath(file)
if file_abs_path then
DocSettings:open(file_abs_path):purge()
end
@ -54,7 +56,7 @@ function filemanagerutil.resetDocumentSettings(file)
last_page = true,
last_xpointer = true,
}
local file_abs_path = util.realpath(file)
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
@ -67,54 +69,32 @@ function filemanagerutil.resetDocumentSettings(file)
end
end
-- Get a document's status ("new", "reading", "complete", or "abandoned")
-- Get a document status ("new", "reading", "complete", or "abandoned")
function filemanagerutil.getStatus(file)
local status = "new"
if DocSettings:hasSidecarFile(file) then
local docinfo = DocSettings:open(file) -- no io handles created, do not close
if docinfo.data.summary and docinfo.data.summary.status and docinfo.data.summary.status ~= "" then
status = docinfo.data.summary.status
else
status = "reading"
local summary = DocSettings:open(file):readSetting("summary")
if summary and summary.status and summary.status ~= "" then
return summary.status
end
return "reading"
end
return status
return "new"
end
-- Set a document's status
-- 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 docinfo = DocSettings:open(file)
local summary
if docinfo.data.summary and docinfo.data.summary.status then
-- Book already had the full BookStatus table in its sidecar, easy peasy!
docinfo.data.summary.status = status
docinfo.data.summary.modified = os.date("%Y-%m-%d", os.time())
summary = docinfo.data.summary
else
-- No BookStatus table, create a minimal one...
if docinfo.data.summary then
-- Err, a summary table with no status entry? Should never happen...
summary = { status = status }
-- Append the status entry to the existing summary...
require("util").tableMerge(docinfo.data.summary, summary)
docinfo.data.summary.modified = os.date("%Y-%m-%d", os.time())
summary = docinfo.data.summary
else
-- No summary table at all, create a minimal one
summary = {
status = status,
modified = os.date("%Y-%m-%d", os.time())
}
end
end
docinfo:saveSetting("summary", summary)
docinfo:flush()
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
-- Generate all book status file dialog buttons in a row
function filemanagerutil.genStatusButtonsRow(file, caller_callback)
local status = filemanagerutil.getStatus(file)
function filemanagerutil.genStatusButtonsRow(file, caller_callback, current_status)
local status = current_status or filemanagerutil.getStatus(file)
local function genStatusButton(to_status)
local status_text = {
reading = _("Reading"),
@ -122,7 +102,7 @@ function filemanagerutil.genStatusButtonsRow(file, caller_callback)
complete = _("Finished"),
}
return {
text = status_text[to_status],
text = status_text[to_status] .. (status == to_status and "" or ""),
id = to_status, -- used by covermenu
enabled = status ~= to_status,
callback = function()
@ -138,15 +118,16 @@ function filemanagerutil.genStatusButtonsRow(file, caller_callback)
}
end
-- Generate a "Reset settings" file dialog button
function filemanagerutil.genResetSettingsButton(file, currently_opened_file, caller_callback)
-- Generate "Reset" file dialog button
function filemanagerutil.genResetSettingsButton(file, caller_callback, button_disabled)
return {
text = _("Reset"),
id = "reset", -- used by covermenu
enabled = file ~= currently_opened_file and DocSettings:hasSidecarFile(util.realpath(file)),
enabled = not button_disabled and DocSettings:hasSidecarFile(ffiutil.realpath(file)),
callback = function()
UIManager:show(ConfirmBox:new{
text = T(_("Reset this document?\n\n%1\n\nAll document progress, settings, bookmarks, highlights, and notes will be permanently lost."),
text = T(_("Reset this document?") .. "\n\n%1\n\n" ..
_("Document progress, settings, bookmarks, highlights and notes will be permanently lost."),
BD.filepath(file)),
ok_text = _("Reset"),
ok_callback = function()
@ -159,4 +140,42 @@ function filemanagerutil.genResetSettingsButton(file, currently_opened_file, cal
}
end
-- Generate "Execute script" file dialog button
function filemanagerutil.genExecuteScriptButton(file, caller_callback)
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

@ -1,4 +1,3 @@
local BD = require("ui/bidi")
local BookStatusWidget = require("ui/widget/bookstatuswidget")
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local Device = require("device")
@ -8,7 +7,6 @@ local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local util = require("util")
local _ = require("gettext")
local T = require("ffi/util").template
local ReaderStatus = WidgetContainer:extend{
document = nil,
@ -36,46 +34,39 @@ end
function ReaderStatus:onEndOfBook()
Device:performHapticFeedback("CONTEXT_CLICK")
local settings = G_reader_settings:readSetting("end_document_action")
local choose_action
local collate = true
local QuickStart = require("ui/quickstart")
local last_file = G_reader_settings:readSetting("lastfile")
if last_file and last_file == QuickStart.quickstart_filename then
if last_file == QuickStart.quickstart_filename then
self:openFileBrowser()
return
end
if G_reader_settings:readSetting("collate") == "access" then
collate = false
end
-- Should we start by marking the book as read?
if G_reader_settings:isTrue("end_document_auto_mark") then
self:onMarkBook(true)
end
local top_wg = UIManager:getTopmostVisibleWidget() or {}
if (settings == "pop-up" or settings == nil) and top_wg.name ~= "end_document" then
local next_file_enabled = G_reader_settings:readSetting("collate") ~= "access"
local settings = G_reader_settings:readSetting("end_document_action")
local top_widget = UIManager:getTopmostVisibleWidget() or {}
if (settings == "pop-up" or settings == nil) and top_widget.name ~= "end_document" then
local button_dialog
local buttons = {
{
{
text_func = function()
if self.settings.data.summary and self.settings.data.summary.status == "complete" then
return _("Mark as reading")
else
return _("Mark as finished")
end
return self.summary.status == "complete" and _("Mark as reading") or _("Mark as finished")
end,
callback = function()
self:onMarkBook()
UIManager:close(choose_action)
UIManager:close(button_dialog)
end,
},
{
text = _("Book status"),
callback = function()
self:onShowBookStatus()
UIManager:close(choose_action)
UIManager:close(button_dialog)
end,
},
@ -85,15 +76,15 @@ function ReaderStatus:onEndOfBook()
text = _("Go to beginning"),
callback = function()
self.ui:handleEvent(Event:new("GoToBeginning"))
UIManager:close(choose_action)
UIManager:close(button_dialog)
end,
},
{
text = _("Open next file"),
enabled = collate,
enabled = next_file_enabled,
callback = function()
self:onOpenNextDocumentInFolder()
UIManager:close(choose_action)
UIManager:close(button_dialog)
end,
},
},
@ -101,46 +92,38 @@ function ReaderStatus:onEndOfBook()
{
text = _("Delete file"),
callback = function()
self:deleteFile(self.document.file, false)
UIManager:close(choose_action)
self:deleteFile()
UIManager:close(button_dialog)
end,
},
{
text = _("File browser"),
callback = function()
self:openFileBrowser()
UIManager:close(choose_action)
end,
},
},
{
{
text = _("Cancel"),
callback = function()
UIManager:close(choose_action)
UIManager:close(button_dialog)
end,
},
},
}
choose_action = ButtonDialogTitle:new{
button_dialog = ButtonDialogTitle:new{
name = "end_document",
title = _("You've reached the end of the document.\nWhat would you like to do?"),
title_align = "center",
buttons = buttons,
}
UIManager:show(choose_action)
UIManager:show(button_dialog)
elseif settings == "book_status" then
self:onShowBookStatus()
elseif settings == "next_file" then
if G_reader_settings:readSetting("collate") ~= "access" then
if next_file_enabled then
local info = InfoMessage:new{
text = _("Searching next file…"),
}
UIManager:show(info)
UIManager:forceRePaint()
UIManager:close(info)
-- Delay until the next tick, as this will destroy the Document instance, but we may not be the final Event caught by said Document...
-- Delay until the next tick, as this will destroy the Document instance,
-- but we may not be the final Event caught by said Document...
UIManager:nextTick(function()
self:onOpenNextDocumentInFolder()
end)
@ -171,7 +154,7 @@ function ReaderStatus:onEndOfBook()
elseif settings == "delete_file" then
-- Ditto
UIManager:nextTick(function()
self:deleteFile(self.document.file, true)
self:deleteFile()
end)
end
end
@ -200,28 +183,17 @@ function ReaderStatus:onOpenNextDocumentInFolder()
end
end
function ReaderStatus:deleteFile(file, text_end_book)
local ConfirmBox = require("ui/widget/confirmbox")
local message_end_book = ""
if text_end_book then
message_end_book = "You've reached the end of the document.\n"
function ReaderStatus:deleteFile()
self.settings:flush() -- enable additional warning text for newly opened file
local FileManager = require("apps/filemanager/filemanager")
local function pre_delete_callback()
self.ui:onClose()
end
UIManager:show(ConfirmBox:new{
text = T(_("%1Are you sure that you want to delete this file?\n%2\nIf you delete a file, it is permanently lost."), message_end_book, BD.filepath(file)),
ok_text = _("Delete"),
ok_callback = function()
local FileManager = require("apps/filemanager/filemanager")
self.ui:onClose()
FileManager:deleteFile(file)
require("readhistory"):fileDeleted(file) -- (will update "lastfile")
if FileManager.instance then
FileManager.instance.file_chooser:refreshPath()
else
local path = util.splitFilePathName(file)
FileManager:showFiles(path)
end
end,
})
local function post_delete_callback()
local path = util.splitFilePathName(self.document.file)
FileManager:showFiles(path)
end
FileManager:showDeleteFileDialog(self.document.file, post_delete_callback, pre_delete_callback)
end
function ReaderStatus:onShowBookStatus(before_show_callback)
@ -240,31 +212,18 @@ function ReaderStatus:onShowBookStatus(before_show_callback)
return true
end
-- If mark_read is true then we change status only from reading/abandoned to read (complete).
-- Otherwise we change status from reading/abandoned to read or from read to reading.
-- If mark_read is true then we change status only from reading/abandoned to complete.
-- Otherwise we change status from reading/abandoned to complete or from complete to reading.
function ReaderStatus:onMarkBook(mark_read)
if self.settings.data.summary then
if self.settings.data.summary.status and self.settings.data.summary.status == "complete" then
if mark_read then
-- Keep mark as finished.
self.settings.data.summary.status = "complete"
else
-- Change current status from read (complete) to reading
self.settings.data.summary.status = "reading"
end
else
self.settings.data.summary.status = "complete"
end
else
self.settings.data.summary = {status = "complete"}
end
self.summary.status = (not mark_read and self.summary.status == "complete") and "reading" or "complete"
-- If History is called over Reader, it will read the file to get the book status, so save and flush
self.settings:saveSetting("summary", self.settings.data.summary)
self.settings:saveSetting("summary", self.summary)
self.settings:flush()
end
function ReaderStatus:onReadSettings(config)
self.settings = config
self.summary = config:readSetting("summary") or {}
end
return ReaderStatus

@ -43,6 +43,8 @@ local nb_drawings_since_last_collectgarbage = 0
-- in the real Menu class or instance
local CoverMenu = {}
local book_statuses = {"reading", "abandoned", "complete"}
function CoverMenu:updateCache(file, status)
if self.cover_info_cache and self.cover_info_cache[file] then
if status then
@ -348,8 +350,9 @@ function CoverMenu:updateItems(select_number)
end
-- Fudge the status change button callbacks to also update the cover_info_cache
for _, status in ipairs({"reading", "abandoned", "complete"}) do
for _, status in ipairs(book_statuses) do
button = self.file_dialog.button_table:getButtonById(status)
if not button then break end -- status buttons are not shown
local orig_status_callback = button.callback
button.callback = function()
-- Update the cache
@ -501,16 +504,15 @@ function CoverMenu:onHistoryMenuHold(item)
end
-- Fudge the status change button callbacks to also update the cover_info_cache
for _, status in ipairs({"reading", "abandoned", "complete"}) do
for _, status in ipairs(book_statuses) do
button = self.histfile_dialog.button_table:getButtonById(status)
if button then
local orig_status_callback = button.callback
button.callback = function()
-- Update the cache
self:updateCache(file, status)
-- And then set the status on file as expected
orig_status_callback()
end
if not button then break end -- status buttons are not shown
local orig_status_callback = button.callback
button.callback = function()
-- Update the cache
self:updateCache(file, status)
-- And then set the status on file as expected
orig_status_callback()
end
end
@ -648,8 +650,9 @@ function CoverMenu:onCollectionsMenuHold(item)
end
-- Fudge the status change button callbacks to also update the cover_info_cache
for _, status in ipairs({"reading", "abandoned", "complete"}) do
for _, status in ipairs(book_statuses) do
button = self.collfile_dialog.button_table:getButtonById(status)
if not button then break end -- status buttons are not shown
local orig_status_callback = button.callback
button.callback = function()
-- Update the cache
@ -694,7 +697,7 @@ function CoverMenu:onCloseWidget()
-- Propagate a call to free() to all our sub-widgets, to release memory used by their _bb
self.item_group:free()
-- Clean any short term cache (used by ListMenu to cache some DocSettings info)
-- Clean any short term cache (used by ListMenu to cache some Doc Settings info)
self.cover_info_cache = nil
-- Force garbage collecting when leaving too

@ -32,11 +32,11 @@ describe("FileManager module", function()
assert.Equals(w.text, "File not found:\n"..tmp_fn)
end
assert.is_nil(lfs.attributes(tmp_fn))
filemanager:deleteFile(tmp_fn)
filemanager:deleteFile(tmp_fn, true)
UIManager.show = old_show
filemanager:onClose()
end)
it("should not delete settings for non-document file", function()
it("should not delete not empty sidecar folder", function()
local filemanager = FileManager:new{
dimen = Screen:getSize(),
root_path = "../../test",
@ -47,30 +47,32 @@ describe("FileManager module", function()
local tmp_sidecar = docsettings:getSidecarDir(util.realpath(tmp_fn))
lfs.mkdir(tmp_sidecar)
local tmp_history = docsettings:getHistoryPath(tmp_fn)
local tmpfp = io.open(tmp_history, "w")
tmpfp:write("{}")
tmpfp:close()
local tmp_sidecar_file = docsettings:getSidecarFile(util.realpath(tmp_fn))
local tmp_sidecar_file_foo = tmp_sidecar_file .. ".foo" -- non-docsettings file
local tmpsf = io.open(tmp_sidecar_file, "w")
tmpsf:write("{}")
tmpsf:close()
util.copyFile(tmp_sidecar_file, tmp_sidecar_file_foo)
local old_show = UIManager.show
-- make sure file exists
assert.is_not_nil(lfs.attributes(tmp_fn))
assert.is_not_nil(lfs.attributes(tmp_sidecar))
assert.is_not_nil(lfs.attributes(tmp_history))
assert.is_not_nil(lfs.attributes(tmp_sidecar_file))
assert.is_not_nil(lfs.attributes(tmp_sidecar_file_foo))
UIManager.show = function(self, w)
assert.Equals(w.text, "Deleted file:\n"..tmp_fn)
end
filemanager:deleteFile(tmp_fn)
filemanager:deleteFile(tmp_fn, true)
UIManager.show = old_show
filemanager:onClose()
-- make sure history file exists
-- make sure sdr folder exists
assert.is_nil(lfs.attributes(tmp_fn))
assert.is_not_nil(lfs.attributes(tmp_sidecar))
assert.is_not_nil(lfs.attributes(tmp_history))
os.remove(tmp_sidecar_file_foo)
os.remove(tmp_sidecar)
os.remove(tmp_history)
end)
it("should delete document with its settings", function()
local filemanager = FileManager:new{
@ -83,6 +85,10 @@ describe("FileManager module", function()
local tmp_sidecar = docsettings:getSidecarDir(util.realpath(tmp_fn))
lfs.mkdir(tmp_sidecar)
local tmp_sidecar_file = docsettings:getSidecarFile(util.realpath(tmp_fn))
local tmpsf = io.open(tmp_sidecar_file, "w")
tmpsf:write("{}")
tmpsf:close()
local tmp_history = docsettings:getHistoryPath(tmp_fn)
local tmpfp = io.open(tmp_history, "w")
tmpfp:write("{}")
@ -97,7 +103,7 @@ describe("FileManager module", function()
UIManager.show = function(self, w)
assert.Equals(w.text, "Deleted file:\n"..tmp_fn)
end
filemanager:deleteFile(tmp_fn)
filemanager:deleteFile(tmp_fn, true)
UIManager.show = old_show
filemanager:onClose()

Loading…
Cancel
Save