mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
File browser, Collection: improve group actions (#11178)
Maintain correct records in History and Favorites when moving/deleting folders or group of files. Optimize Collection module to minimize storage requests.
This commit is contained in:
@@ -57,6 +57,10 @@ local FileManager = InputContainer:extend{
|
|||||||
cp_bin = Device:isAndroid() and "/system/bin/cp" or "/bin/cp",
|
cp_bin = Device:isAndroid() and "/system/bin/cp" or "/bin/cp",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function isFile(file)
|
||||||
|
return lfs.attributes(file, "mode") == "file"
|
||||||
|
end
|
||||||
|
|
||||||
function FileManager:onSetRotationMode(rotation)
|
function FileManager:onSetRotationMode(rotation)
|
||||||
if rotation ~= nil and rotation ~= Screen:getRotationMode() then
|
if rotation ~= nil and rotation ~= Screen:getRotationMode() then
|
||||||
Screen:setRotationMode(rotation)
|
Screen:setRotationMode(rotation)
|
||||||
@@ -190,7 +194,7 @@ function FileManager:setupLayout()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function file_chooser:showFileDialog(file) -- luacheck: ignore
|
function file_chooser:showFileDialog(file) -- luacheck: ignore
|
||||||
local is_file = lfs.attributes(file, "mode") == "file"
|
local is_file = isFile(file)
|
||||||
local is_folder = lfs.attributes(file, "mode") == "directory"
|
local is_folder = lfs.attributes(file, "mode") == "directory"
|
||||||
local is_not_parent_folder = BaseUtil.basename(file) ~= ".."
|
local is_not_parent_folder = BaseUtil.basename(file) ~= ".."
|
||||||
|
|
||||||
@@ -220,7 +224,7 @@ function FileManager:setupLayout()
|
|||||||
enabled = file_manager.clipboard and true or false,
|
enabled = file_manager.clipboard and true or false,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(self.file_dialog)
|
UIManager:close(self.file_dialog)
|
||||||
file_manager:pasteHere(file)
|
file_manager:pasteFileFromClipboard(file)
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -514,20 +518,9 @@ function FileManager:tapPlus()
|
|||||||
text = _("Copy"),
|
text = _("Copy"),
|
||||||
enabled = actions_enabled,
|
enabled = actions_enabled,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:show(ConfirmBox:new{
|
|
||||||
text = _("Copy selected files to the current folder?"),
|
|
||||||
ok_text = _("Copy"),
|
|
||||||
ok_callback = function()
|
|
||||||
UIManager:close(self.file_dialog)
|
|
||||||
self.cutfile = false
|
self.cutfile = false
|
||||||
for file in pairs(self.selected_files) do
|
self:showCopyMoveSelectedFilesDialog(close_dialog_callback)
|
||||||
self.clipboard = file
|
|
||||||
self:pasteHere()
|
|
||||||
end
|
|
||||||
self:onToggleSelectMode()
|
|
||||||
end,
|
end,
|
||||||
})
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -543,20 +536,9 @@ function FileManager:tapPlus()
|
|||||||
text = _("Move"),
|
text = _("Move"),
|
||||||
enabled = actions_enabled,
|
enabled = actions_enabled,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:show(ConfirmBox:new{
|
|
||||||
text = _("Move selected files to the current folder?"),
|
|
||||||
ok_text = _("Move"),
|
|
||||||
ok_callback = function()
|
|
||||||
UIManager:close(self.file_dialog)
|
|
||||||
self.cutfile = true
|
self.cutfile = true
|
||||||
for file in pairs(self.selected_files) do
|
self:showCopyMoveSelectedFilesDialog(close_dialog_callback)
|
||||||
self.clipboard = file
|
|
||||||
self:pasteHere()
|
|
||||||
end
|
|
||||||
self:onToggleSelectMode()
|
|
||||||
end,
|
end,
|
||||||
})
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -565,7 +547,9 @@ function FileManager:tapPlus()
|
|||||||
enabled = actions_enabled,
|
enabled = actions_enabled,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(self.file_dialog)
|
UIManager:close(self.file_dialog)
|
||||||
self.selected_files = {}
|
for file in pairs (self.selected_files) do
|
||||||
|
self.selected_files[file] = nil
|
||||||
|
end
|
||||||
self:onRefresh()
|
self:onRefresh()
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
@@ -578,10 +562,7 @@ function FileManager:tapPlus()
|
|||||||
ok_text = _("Delete"),
|
ok_text = _("Delete"),
|
||||||
ok_callback = function()
|
ok_callback = function()
|
||||||
UIManager:close(self.file_dialog)
|
UIManager:close(self.file_dialog)
|
||||||
for file in pairs(self.selected_files) do
|
self:deleteSelectedFiles()
|
||||||
self:deleteFile(file, true) -- only files can be selected
|
|
||||||
end
|
|
||||||
self:onToggleSelectMode()
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
@@ -642,7 +623,7 @@ function FileManager:tapPlus()
|
|||||||
enabled = self.clipboard and true or false,
|
enabled = self.clipboard and true or false,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(self.file_dialog)
|
UIManager:close(self.file_dialog)
|
||||||
self:pasteHere()
|
self:pasteFileFromClipboard()
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -651,7 +632,7 @@ function FileManager:tapPlus()
|
|||||||
text = _("Set as HOME folder"),
|
text = _("Set as HOME folder"),
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(self.file_dialog)
|
UIManager:close(self.file_dialog)
|
||||||
self:setHome(self.file_chooser.path)
|
self:setHome()
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -850,69 +831,140 @@ function FileManager:cutFile(file)
|
|||||||
self.clipboard = file
|
self.clipboard = file
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManager:pasteHere(file)
|
function FileManager:pasteFileFromClipboard(file)
|
||||||
local orig_file = BaseUtil.realpath(self.clipboard)
|
local orig_file = BaseUtil.realpath(self.clipboard)
|
||||||
local orig_name = BaseUtil.basename(self.clipboard)
|
local orig_name = BaseUtil.basename(orig_file)
|
||||||
local dest_path = BaseUtil.realpath(file or self.file_chooser.path)
|
local dest_path = BaseUtil.realpath(file or self.file_chooser.path)
|
||||||
dest_path = lfs.attributes(dest_path, "mode") == "directory" and dest_path or dest_path:match("(.*/)")
|
dest_path = isFile(dest_path) and dest_path:match("(.*/)") or dest_path
|
||||||
local dest_file = BaseUtil.joinPath(dest_path, orig_name)
|
local dest_file = BaseUtil.joinPath(dest_path, orig_name)
|
||||||
local is_file = lfs.attributes(orig_file, "mode") == "file"
|
local is_file = isFile(orig_file)
|
||||||
|
|
||||||
local function infoCopyFile()
|
|
||||||
if self:copyRecursive(orig_file, dest_path) then
|
|
||||||
if is_file then
|
|
||||||
DocSettings.updateLocation(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 self:moveFile(orig_file, dest_path) then
|
|
||||||
if is_file then
|
|
||||||
DocSettings.updateLocation(orig_file, dest_file)
|
|
||||||
ReadHistory:updateItemByPath(orig_file, dest_file) -- (will update "lastfile" if needed)
|
|
||||||
else
|
|
||||||
ReadHistory:updateItemsByPath(orig_file, dest_file)
|
|
||||||
end
|
|
||||||
ReadCollection:updateItemByPath(orig_file, dest_file)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
local function doPaste()
|
local function doPaste()
|
||||||
local ok = self.cutfile and infoMoveFile() or infoCopyFile()
|
local ok
|
||||||
|
if self.cutfile then
|
||||||
|
ok = self:moveFile(orig_file, dest_path)
|
||||||
|
else
|
||||||
|
ok = self:copyRecursive(orig_file, dest_path)
|
||||||
|
end
|
||||||
if ok then
|
if ok then
|
||||||
self:onRefresh()
|
if is_file then -- move or copy sdr
|
||||||
|
DocSettings.updateLocation(orig_file, dest_file, not self.cutfile)
|
||||||
|
end
|
||||||
|
if self.cutfile then -- for move only
|
||||||
|
if is_file then
|
||||||
|
ReadHistory:updateItem(orig_file, dest_file)
|
||||||
|
ReadCollection:updateItem(orig_file, dest_file)
|
||||||
|
else
|
||||||
|
ReadHistory:updateItemsByPath(orig_file, dest_file)
|
||||||
|
ReadCollection:updateItemsByPath(orig_file, dest_file)
|
||||||
|
end
|
||||||
|
end
|
||||||
self.clipboard = nil
|
self.clipboard = nil
|
||||||
|
self:onRefresh()
|
||||||
|
else
|
||||||
|
local text = self.cutfile and "Failed to move:\n%1\nto:\n%2"
|
||||||
|
or "Failed to copy:\n%1\nto:\n%2"
|
||||||
|
UIManager:show(InfoMessage:new{
|
||||||
|
text = T(_(text), BD.filepath(orig_name), BD.dirpath(dest_path)),
|
||||||
|
icon = "notice-warning",
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mode = lfs.attributes(dest_file, "mode")
|
local mode_dest = lfs.attributes(dest_file, "mode")
|
||||||
if mode then
|
if mode_dest then -- file or folder with target name already exists
|
||||||
|
local can_overwrite = (mode_dest == "file") == is_file
|
||||||
|
local text = can_overwrite == is_file and T(_("File already exists:\n%1"), BD.filename(orig_name))
|
||||||
|
or T(_("Folder already exists:\n%1"), BD.directory(orig_name))
|
||||||
|
if can_overwrite then
|
||||||
UIManager:show(ConfirmBox:new{
|
UIManager:show(ConfirmBox:new{
|
||||||
text = mode == "file" and T(_("File already exists:\n%1\nOverwrite file?"), BD.filename(orig_name))
|
text = text,
|
||||||
or T(_("Folder already exists:\n%1\nOverwrite folder?"), BD.directory(orig_name)),
|
|
||||||
ok_text = _("Overwrite"),
|
ok_text = _("Overwrite"),
|
||||||
ok_callback = function()
|
ok_callback = function()
|
||||||
doPaste()
|
doPaste()
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
else
|
||||||
|
UIManager:show(InfoMessage:new{
|
||||||
|
text = text,
|
||||||
|
icon = "notice-warning",
|
||||||
|
})
|
||||||
|
end
|
||||||
else
|
else
|
||||||
doPaste()
|
doPaste()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function FileManager:showCopyMoveSelectedFilesDialog(close_callback)
|
||||||
|
local text, ok_text
|
||||||
|
if self.cutfile then
|
||||||
|
text = _("Move selected files to the current folder?")
|
||||||
|
ok_text = _("Move")
|
||||||
|
else
|
||||||
|
text = _("Copy selected files to the current folder?")
|
||||||
|
ok_text = _("Copy")
|
||||||
|
end
|
||||||
|
local confirmbox, check_button_overwrite
|
||||||
|
confirmbox = ConfirmBox:new{
|
||||||
|
text = text,
|
||||||
|
ok_text = ok_text,
|
||||||
|
ok_callback = function()
|
||||||
|
close_callback()
|
||||||
|
self:pasteSelectedFiles(check_button_overwrite.checked)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
check_button_overwrite = CheckButton:new{
|
||||||
|
text = _("overwrite existing files"),
|
||||||
|
checked = true,
|
||||||
|
parent = confirmbox,
|
||||||
|
}
|
||||||
|
confirmbox:addWidget(check_button_overwrite)
|
||||||
|
UIManager:show(confirmbox)
|
||||||
|
end
|
||||||
|
|
||||||
|
function FileManager:pasteSelectedFiles(overwrite)
|
||||||
|
local dest_path = BaseUtil.realpath(self.file_chooser.path)
|
||||||
|
local ok_files = {}
|
||||||
|
for orig_file in pairs(self.selected_files) do
|
||||||
|
local orig_name = BaseUtil.basename(orig_file)
|
||||||
|
local dest_file = BaseUtil.joinPath(dest_path, orig_name)
|
||||||
|
local ok
|
||||||
|
local dest_mode = lfs.attributes(dest_file, "mode")
|
||||||
|
if not dest_mode or (dest_mode == "file" and overwrite) then
|
||||||
|
if self.cutfile then
|
||||||
|
ok = self:moveFile(orig_file, dest_path)
|
||||||
|
else
|
||||||
|
ok = self:copyRecursive(orig_file, dest_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ok then
|
||||||
|
DocSettings.updateLocation(orig_file, dest_file, not self.cutfile)
|
||||||
|
ok_files[orig_file] = true
|
||||||
|
self.selected_files[orig_file] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local skipped_nb = util.tableSize(self.selected_files)
|
||||||
|
if util.tableSize(ok_files) > 0 then
|
||||||
|
if self.cutfile then -- for move only
|
||||||
|
ReadHistory:updateItems(ok_files, dest_path)
|
||||||
|
ReadCollection:updateItems(ok_files, dest_path)
|
||||||
|
end
|
||||||
|
if skipped_nb > 0 then
|
||||||
|
self:onRefresh()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if skipped_nb > 0 then -- keep select mode on
|
||||||
|
local text = self.cutfile and T(N_("1 file was not moved", "%1 files were not moved", skipped_nb), skipped_nb)
|
||||||
|
or T(N_("1 file was not copied", "%1 files were not copied", skipped_nb), skipped_nb)
|
||||||
|
UIManager:show(InfoMessage:new{
|
||||||
|
text = text,
|
||||||
|
icon = "notice-warning",
|
||||||
|
})
|
||||||
|
else
|
||||||
|
self:onToggleSelectMode()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function FileManager:createFolder()
|
function FileManager:createFolder()
|
||||||
local input_dialog, check_button_enter_folder
|
local input_dialog, check_button_enter_folder
|
||||||
input_dialog = InputDialog:new{
|
input_dialog = InputDialog:new{
|
||||||
@@ -961,11 +1013,18 @@ function FileManager:createFolder()
|
|||||||
input_dialog:onShowKeyboard()
|
input_dialog:onShowKeyboard()
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManager:showDeleteFileDialog(file, post_delete_callback, pre_delete_callback)
|
function FileManager:showDeleteFileDialog(filepath, post_delete_callback, pre_delete_callback)
|
||||||
local file_abs_path = BaseUtil.realpath(file)
|
local file = BaseUtil.realpath(filepath)
|
||||||
local is_file = lfs.attributes(file_abs_path, "mode") == "file"
|
if file == nil then
|
||||||
|
UIManager:show(InfoMessage:new{
|
||||||
|
text = T(_("File not found:\n%1"), BD.filepath(filepath)),
|
||||||
|
icon = "notice-warning",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local is_file = isFile(file)
|
||||||
local text = (is_file and _("Delete file permanently?") or _("Delete folder permanently?")) .. "\n\n" .. BD.filepath(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
|
if is_file and DocSettings:hasSidecarFile(file) then
|
||||||
text = text .. "\n\n" .. _("Book settings, highlights and notes will be deleted.")
|
text = text .. "\n\n" .. _("Book settings, highlights and notes will be deleted.")
|
||||||
end
|
end
|
||||||
UIManager:show(ConfirmBox:new{
|
UIManager:show(ConfirmBox:new{
|
||||||
@@ -983,35 +1042,54 @@ function FileManager:showDeleteFileDialog(file, post_delete_callback, pre_delete
|
|||||||
end
|
end
|
||||||
|
|
||||||
function FileManager:deleteFile(file, is_file)
|
function FileManager:deleteFile(file, is_file)
|
||||||
local file_abs_path = BaseUtil.realpath(file)
|
|
||||||
if file_abs_path == nil then
|
|
||||||
UIManager:show(InfoMessage:new{
|
|
||||||
text = T(_("File not found:\n%1"), BD.filepath(file)),
|
|
||||||
icon = "notice-warning",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok, err
|
|
||||||
if is_file then
|
if is_file then
|
||||||
ok, err = os.remove(file_abs_path)
|
local ok = os.remove(file)
|
||||||
else
|
if ok then
|
||||||
ok, err = BaseUtil.purgeDir(file_abs_path)
|
DocSettings.updateLocation(file) -- delete sdr
|
||||||
end
|
|
||||||
if ok and not err then
|
|
||||||
if is_file then
|
|
||||||
DocSettings.updateLocation(file)
|
|
||||||
ReadHistory:fileDeleted(file)
|
ReadHistory:fileDeleted(file)
|
||||||
else
|
ReadCollection:removeItem(file)
|
||||||
ReadHistory:folderDeleted(file)
|
|
||||||
end
|
|
||||||
ReadCollection:removeItemByPath(file, not is_file)
|
|
||||||
return true
|
return true
|
||||||
|
end
|
||||||
else
|
else
|
||||||
|
local ok = BaseUtil.purgeDir(file)
|
||||||
|
if ok then
|
||||||
|
ReadHistory:folderDeleted(file) -- will delete sdr
|
||||||
|
ReadCollection:removeItemsByPath(file)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
UIManager:show(InfoMessage:new{
|
UIManager:show(InfoMessage:new{
|
||||||
text = T(_("Failed to delete:\n%1"), BD.filepath(file)),
|
text = T(_("Failed to delete:\n%1"), BD.filepath(file)),
|
||||||
icon = "notice-warning",
|
icon = "notice-warning",
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function FileManager:deleteSelectedFiles()
|
||||||
|
local ok_files = {}
|
||||||
|
for orig_file in pairs(self.selected_files) do
|
||||||
|
local file_abs_path = BaseUtil.realpath(orig_file)
|
||||||
|
local ok = file_abs_path and os.remove(file_abs_path)
|
||||||
|
if ok then
|
||||||
|
DocSettings.updateLocation(file_abs_path) -- delete sdr
|
||||||
|
ok_files[orig_file] = true
|
||||||
|
self.selected_files[orig_file] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local skipped_nb = util.tableSize(self.selected_files)
|
||||||
|
if util.tableSize(ok_files) > 0 then
|
||||||
|
ReadHistory:removeItems(ok_files)
|
||||||
|
ReadCollection:removeItems(ok_files)
|
||||||
|
if skipped_nb > 0 then
|
||||||
|
self:onRefresh()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if skipped_nb > 0 then -- keep select mode on
|
||||||
|
UIManager:show(InfoMessage:new{
|
||||||
|
text = T(N_("Failed to delete 1 file.", "Failed to delete %1 files.", skipped_nb), skipped_nb),
|
||||||
|
icon = "notice-warning",
|
||||||
|
})
|
||||||
|
else
|
||||||
|
self:onToggleSelectMode()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1052,11 +1130,12 @@ function FileManager:renameFile(file, basename, is_file)
|
|||||||
if self:moveFile(file, dest) then
|
if self:moveFile(file, dest) then
|
||||||
if is_file then
|
if is_file then
|
||||||
DocSettings.updateLocation(file, dest)
|
DocSettings.updateLocation(file, dest)
|
||||||
ReadHistory:updateItemByPath(file, dest) -- (will update "lastfile" if needed)
|
ReadHistory:updateItem(file, dest) -- (will update "lastfile" if needed)
|
||||||
|
ReadCollection:updateItem(file, dest)
|
||||||
else
|
else
|
||||||
ReadHistory:updateItemsByPath(file, dest)
|
ReadHistory:updateItemsByPath(file, dest)
|
||||||
|
ReadCollection:updateItemsByPath(file, dest)
|
||||||
end
|
end
|
||||||
ReadCollection:updateItemByPath(file, dest)
|
|
||||||
self:onRefresh()
|
self:onRefresh()
|
||||||
else
|
else
|
||||||
UIManager:show(InfoMessage:new{
|
UIManager:show(InfoMessage:new{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
|||||||
local _ = require("gettext")
|
local _ = require("gettext")
|
||||||
|
|
||||||
local FileManagerCollection = WidgetContainer:extend{
|
local FileManagerCollection = WidgetContainer:extend{
|
||||||
coll_menu_title = _("Favorites"),
|
title = _("Favorites"),
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileManagerCollection:init()
|
function FileManagerCollection:init()
|
||||||
@@ -19,28 +19,36 @@ end
|
|||||||
|
|
||||||
function FileManagerCollection:addToMainMenu(menu_items)
|
function FileManagerCollection:addToMainMenu(menu_items)
|
||||||
menu_items.collections = {
|
menu_items.collections = {
|
||||||
text = self.coll_menu_title,
|
text = self.title,
|
||||||
callback = function()
|
callback = function()
|
||||||
self:onShowColl("favorites")
|
self:onShowColl()
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:updateItemTable()
|
function FileManagerCollection:updateItemTable()
|
||||||
-- Try to stay on current page.
|
local item_table = {}
|
||||||
local select_number = nil
|
for _, item in pairs(ReadCollection.coll[self.coll_menu.collection_name]) do
|
||||||
if self.coll_menu.page and self.coll_menu.perpage then
|
table.insert(item_table, item)
|
||||||
select_number = (self.coll_menu.page - 1) * self.coll_menu.perpage + 1
|
|
||||||
end
|
end
|
||||||
self.coll_menu:switchItemTable(self.coll_menu_title,
|
table.sort(item_table, function(v1, v2) return v1.order < v2.order end)
|
||||||
ReadCollection:prepareList(self.coll_menu.collection), select_number)
|
self.coll_menu:switchItemTable(self.title, item_table, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:onMenuChoice(item)
|
function FileManagerCollection:onMenuChoice(item)
|
||||||
require("apps/reader/readerui"):showReader(item.file)
|
local file = item.file
|
||||||
|
if self.ui.document then
|
||||||
|
if self.ui.document.file ~= file then
|
||||||
|
self.ui:switchDocument(file)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local ReaderUI = require("apps/reader/readerui")
|
||||||
|
ReaderUI:showReader(file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:onMenuHold(item)
|
function FileManagerCollection:onMenuHold(item)
|
||||||
|
local file = item.file
|
||||||
self.collfile_dialog = nil
|
self.collfile_dialog = nil
|
||||||
local function close_dialog_callback()
|
local function close_dialog_callback()
|
||||||
UIManager:close(self.collfile_dialog)
|
UIManager:close(self.collfile_dialog)
|
||||||
@@ -49,46 +57,45 @@ function FileManagerCollection:onMenuHold(item)
|
|||||||
UIManager:close(self.collfile_dialog)
|
UIManager:close(self.collfile_dialog)
|
||||||
self._manager.coll_menu.close_callback()
|
self._manager.coll_menu.close_callback()
|
||||||
end
|
end
|
||||||
local function status_button_callback()
|
local function close_dialog_update_callback()
|
||||||
UIManager:close(self.collfile_dialog)
|
UIManager:close(self.collfile_dialog)
|
||||||
self._manager:updateItemTable()
|
self._manager:updateItemTable()
|
||||||
|
self._manager.files_updated = true
|
||||||
end
|
end
|
||||||
local is_currently_opened = item.file == (self.ui.document and self.ui.document.file)
|
local is_currently_opened = file == (self.ui.document and self.ui.document.file)
|
||||||
|
|
||||||
local buttons = {}
|
local buttons = {}
|
||||||
if not item.dim then
|
local doc_settings_or_file = is_currently_opened and self.ui.doc_settings or file
|
||||||
local doc_settings_or_file = is_currently_opened and self.ui.doc_settings or item.file
|
table.insert(buttons, filemanagerutil.genStatusButtonsRow(doc_settings_or_file, close_dialog_update_callback))
|
||||||
table.insert(buttons, filemanagerutil.genStatusButtonsRow(doc_settings_or_file, status_button_callback))
|
|
||||||
table.insert(buttons, {}) -- separator
|
table.insert(buttons, {}) -- separator
|
||||||
end
|
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
filemanagerutil.genResetSettingsButton(item.file, status_button_callback, is_currently_opened),
|
filemanagerutil.genResetSettingsButton(file, close_dialog_update_callback, is_currently_opened),
|
||||||
{
|
{
|
||||||
text = _("Remove from favorites"),
|
text = _("Remove from favorites"),
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(self.collfile_dialog)
|
UIManager:close(self.collfile_dialog)
|
||||||
ReadCollection:removeItem(item.file, self._manager.coll_menu.collection)
|
ReadCollection:removeItem(file, self.collection_name)
|
||||||
self._manager:updateItemTable()
|
self._manager:updateItemTable()
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
filemanagerutil.genShowFolderButton(item.file, close_dialog_menu_callback, item.dim),
|
filemanagerutil.genShowFolderButton(file, close_dialog_menu_callback),
|
||||||
filemanagerutil.genBookInformationButton(item.file, close_dialog_callback, item.dim),
|
filemanagerutil.genBookInformationButton(file, close_dialog_callback),
|
||||||
})
|
})
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
filemanagerutil.genBookCoverButton(item.file, close_dialog_callback, item.dim),
|
filemanagerutil.genBookCoverButton(file, close_dialog_callback),
|
||||||
filemanagerutil.genBookDescriptionButton(item.file, close_dialog_callback, item.dim),
|
filemanagerutil.genBookDescriptionButton(file, close_dialog_callback),
|
||||||
})
|
})
|
||||||
|
|
||||||
if Device:canExecuteScript(item.file) then
|
if Device:canExecuteScript(file) then
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
filemanagerutil.genExecuteScriptButton(item.file, close_dialog_menu_callback)
|
filemanagerutil.genExecuteScriptButton(file, close_dialog_menu_callback)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
self.collfile_dialog = ButtonDialog:new{
|
self.collfile_dialog = ButtonDialog:new{
|
||||||
title = item.text:match("([^/]+)$"),
|
title = item.text,
|
||||||
title_align = "center",
|
title_align = "center",
|
||||||
buttons = buttons,
|
buttons = buttons,
|
||||||
}
|
}
|
||||||
@@ -111,7 +118,8 @@ function FileManagerCollection:MenuSetRotationModeHandler(rotation)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:onShowColl(collection)
|
function FileManagerCollection:onShowColl(collection_name)
|
||||||
|
collection_name = collection_name or ReadCollection.default_collection_name
|
||||||
self.coll_menu = Menu:new{
|
self.coll_menu = Menu:new{
|
||||||
ui = self.ui,
|
ui = self.ui,
|
||||||
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
||||||
@@ -123,33 +131,31 @@ function FileManagerCollection:onShowColl(collection)
|
|||||||
onMenuHold = self.onMenuHold,
|
onMenuHold = self.onMenuHold,
|
||||||
onSetRotationMode = self.MenuSetRotationModeHandler,
|
onSetRotationMode = self.MenuSetRotationModeHandler,
|
||||||
_manager = self,
|
_manager = self,
|
||||||
collection = collection,
|
collection_name = collection_name,
|
||||||
}
|
}
|
||||||
self:updateItemTable()
|
|
||||||
self.coll_menu.close_callback = function()
|
self.coll_menu.close_callback = function()
|
||||||
UIManager:close(self.coll_menu)
|
if self.files_updated then
|
||||||
|
if self.ui.file_chooser then
|
||||||
|
self.ui.file_chooser:refreshPath()
|
||||||
end
|
end
|
||||||
|
self.files_updated = nil
|
||||||
|
end
|
||||||
|
UIManager:close(self.coll_menu)
|
||||||
|
self.coll_menu = nil
|
||||||
|
end
|
||||||
|
self:updateItemTable()
|
||||||
UIManager:show(self.coll_menu)
|
UIManager:show(self.coll_menu)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:showCollDialog()
|
function FileManagerCollection:showCollDialog()
|
||||||
local coll_dialog
|
local coll_dialog
|
||||||
local is_added = self.ui.document and ReadCollection:checkItemExist(self.ui.document.file)
|
|
||||||
local buttons = {
|
local buttons = {
|
||||||
{{
|
{{
|
||||||
text_func = function()
|
text = _("Sort favorites"),
|
||||||
return is_added and _("Remove current book from favorites") or _("Add current book to favorites")
|
|
||||||
end,
|
|
||||||
enabled = self.ui.document and true or false,
|
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(coll_dialog)
|
UIManager:close(coll_dialog)
|
||||||
if is_added then
|
self:sortCollection()
|
||||||
ReadCollection:removeItem(self.ui.document.file)
|
|
||||||
else
|
|
||||||
ReadCollection:addItem(self.ui.document.file)
|
|
||||||
end
|
|
||||||
self:updateItemTable()
|
|
||||||
end,
|
end,
|
||||||
}},
|
}},
|
||||||
{{
|
{{
|
||||||
@@ -164,8 +170,8 @@ function FileManagerCollection:showCollDialog()
|
|||||||
return DocumentRegistry:hasProvider(file)
|
return DocumentRegistry:hasProvider(file)
|
||||||
end,
|
end,
|
||||||
onConfirm = function(file)
|
onConfirm = function(file)
|
||||||
if not ReadCollection:checkItemExist(file) then
|
if not ReadCollection:hasFile(file) then
|
||||||
ReadCollection:addItem(file)
|
ReadCollection:addItem(file, self.coll_menu.collection_name)
|
||||||
self:updateItemTable()
|
self:updateItemTable()
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@@ -173,14 +179,24 @@ function FileManagerCollection:showCollDialog()
|
|||||||
UIManager:show(path_chooser)
|
UIManager:show(path_chooser)
|
||||||
end,
|
end,
|
||||||
}},
|
}},
|
||||||
{{
|
}
|
||||||
text = _("Sort favorites"),
|
if self.ui.document then
|
||||||
|
local has_file = ReadCollection:hasFile(self.ui.document.file)
|
||||||
|
table.insert(buttons, {{
|
||||||
|
text_func = function()
|
||||||
|
return has_file and _("Remove current book from favorites") or _("Add current book to favorites")
|
||||||
|
end,
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(coll_dialog)
|
UIManager:close(coll_dialog)
|
||||||
self:sortCollection()
|
if has_file then
|
||||||
|
ReadCollection:removeItem(self.ui.document.file)
|
||||||
|
else
|
||||||
|
ReadCollection:addItem(self.ui.document.file, self.coll_menu.collection_name)
|
||||||
|
end
|
||||||
|
self:updateItemTable()
|
||||||
end,
|
end,
|
||||||
}},
|
}})
|
||||||
}
|
end
|
||||||
coll_dialog = ButtonDialog:new{
|
coll_dialog = ButtonDialog:new{
|
||||||
buttons = buttons,
|
buttons = buttons,
|
||||||
}
|
}
|
||||||
@@ -188,21 +204,14 @@ function FileManagerCollection:showCollDialog()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function FileManagerCollection:sortCollection()
|
function FileManagerCollection:sortCollection()
|
||||||
local item_table = {}
|
local item_table = ReadCollection:getOrderedCollection(self.coll_menu.collection_name)
|
||||||
for _, v in ipairs(self.coll_menu.item_table) do
|
|
||||||
table.insert(item_table, { text = v.text, label = v.file })
|
|
||||||
end
|
|
||||||
local SortWidget = require("ui/widget/sortwidget")
|
local SortWidget = require("ui/widget/sortwidget")
|
||||||
local sort_widget
|
local sort_widget
|
||||||
sort_widget = SortWidget:new{
|
sort_widget = SortWidget:new{
|
||||||
title = _("Sort favorites"),
|
title = _("Sort favorites"),
|
||||||
item_table = item_table,
|
item_table = item_table,
|
||||||
callback = function()
|
callback = function()
|
||||||
local new_order_table = {}
|
ReadCollection:updateCollectionOrder(self.coll_menu.collection_name, sort_widget.item_table)
|
||||||
for i, v in ipairs(sort_widget.item_table) do
|
|
||||||
table.insert(new_order_table, { file = v.label, order = i })
|
|
||||||
end
|
|
||||||
ReadCollection:writeCollection(new_order_table, self.coll_menu.collection)
|
|
||||||
self:updateItemTable()
|
self:updateItemTable()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ function FileManagerShortcuts:onMenuHold(item)
|
|||||||
text = _("Paste to folder"),
|
text = _("Paste to folder"),
|
||||||
callback = function()
|
callback = function()
|
||||||
UIManager:close(dialog)
|
UIManager:close(dialog)
|
||||||
self._manager.ui:pasteHere(item.folder)
|
self._manager.ui:pasteFileFromClipboard(item.folder)
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -224,15 +224,15 @@ end
|
|||||||
|
|
||||||
function filemanagerutil.genAddRemoveFavoritesButton(file, caller_callback, button_disabled)
|
function filemanagerutil.genAddRemoveFavoritesButton(file, caller_callback, button_disabled)
|
||||||
local ReadCollection = require("readcollection")
|
local ReadCollection = require("readcollection")
|
||||||
local is_added = ReadCollection:checkItemExist(file)
|
local has_file = ReadCollection:hasFile(file)
|
||||||
return {
|
return {
|
||||||
text_func = function()
|
text_func = function()
|
||||||
return is_added and _("Remove from favorites") or _("Add to favorites")
|
return has_file and _("Remove from favorites") or _("Add to favorites")
|
||||||
end,
|
end,
|
||||||
enabled = not button_disabled,
|
enabled = not button_disabled,
|
||||||
callback = function()
|
callback = function()
|
||||||
caller_callback()
|
caller_callback()
|
||||||
if is_added then
|
if has_file then
|
||||||
ReadCollection:removeItem(file)
|
ReadCollection:removeItem(file)
|
||||||
else
|
else
|
||||||
ReadCollection:addItem(file)
|
ReadCollection:addItem(file)
|
||||||
|
|||||||
@@ -2,149 +2,227 @@ local DataStorage = require("datastorage")
|
|||||||
local FFIUtil = require("ffi/util")
|
local FFIUtil = require("ffi/util")
|
||||||
local LuaSettings = require("luasettings")
|
local LuaSettings = require("luasettings")
|
||||||
local lfs = require("libs/libkoreader-lfs")
|
local lfs = require("libs/libkoreader-lfs")
|
||||||
|
local logger = require("logger")
|
||||||
local util = require("util")
|
local util = require("util")
|
||||||
|
|
||||||
local DEFAULT_COLLECTION_NAME = "favorites"
|
|
||||||
local collection_file = DataStorage:getSettingsDir() .. "/collection.lua"
|
local collection_file = DataStorage:getSettingsDir() .. "/collection.lua"
|
||||||
|
|
||||||
local ReadCollection = {}
|
local ReadCollection = {
|
||||||
|
coll = {},
|
||||||
|
last_read_time = 0,
|
||||||
|
default_collection_name = "favorites",
|
||||||
|
}
|
||||||
|
|
||||||
function ReadCollection:read(collection_name)
|
local function buildEntry(file, order, mandatory)
|
||||||
if not collection_name then collection_name = DEFAULT_COLLECTION_NAME end
|
file = FFIUtil.realpath(file)
|
||||||
|
if not file then return end
|
||||||
|
if not mandatory then -- new item
|
||||||
|
local attr = lfs.attributes(file)
|
||||||
|
if not attr or attr.mode ~= "file" then return end
|
||||||
|
mandatory = util.getFriendlySize(attr.size or 0)
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
file = file,
|
||||||
|
text = file:gsub(".*/", ""),
|
||||||
|
mandatory = mandatory,
|
||||||
|
order = order,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:_read()
|
||||||
|
local collection_file_modification_time = lfs.attributes(collection_file, "modification")
|
||||||
|
if collection_file_modification_time then
|
||||||
|
if collection_file_modification_time <= self.last_read_time then return end
|
||||||
|
self.last_read_time = collection_file_modification_time
|
||||||
|
end
|
||||||
local collections = LuaSettings:open(collection_file)
|
local collections = LuaSettings:open(collection_file)
|
||||||
local coll = collections:readSetting(collection_name) or {}
|
if collections:hasNot(self.default_collection_name) then
|
||||||
local coll_max_item = 0
|
collections:saveSetting(self.default_collection_name, {})
|
||||||
for _, v in pairs(coll) do
|
end
|
||||||
if v.order > coll_max_item then
|
logger.dbg("ReadCollection: reading from collection file")
|
||||||
coll_max_item = v.order
|
self.coll = {}
|
||||||
|
for coll_name, collection in pairs(collections.data) do
|
||||||
|
local coll = {}
|
||||||
|
for _, v in ipairs(collection) do
|
||||||
|
local item = buildEntry(v.file, v.order)
|
||||||
|
if item then -- exclude deleted files
|
||||||
|
coll[item.file] = item
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return coll, coll_max_item
|
self.coll[coll_name] = coll
|
||||||
end
|
|
||||||
|
|
||||||
function ReadCollection:readAllCollection()
|
|
||||||
local collection = LuaSettings:open(collection_file)
|
|
||||||
if collection and collection.data then
|
|
||||||
return collection.data
|
|
||||||
else
|
|
||||||
return {}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:prepareList(collection_name)
|
function ReadCollection:write(collection_name)
|
||||||
local data = self:read(collection_name)
|
local collections = LuaSettings:open(collection_file)
|
||||||
local list = {}
|
for coll_name, coll in pairs(self.coll) do
|
||||||
for _, v in pairs(data) do
|
if not collection_name or coll_name == collection_name then
|
||||||
local file_path = FFIUtil.realpath(v.file) or v.file -- keep orig file path of deleted files
|
local data = {}
|
||||||
local file_exists = lfs.attributes(file_path, "mode") == "file"
|
for _, item in pairs(coll) do
|
||||||
table.insert(list, {
|
table.insert(data, { file = item.file, order = item.order })
|
||||||
order = v.order,
|
|
||||||
file = file_path,
|
|
||||||
text = v.file:gsub(".*/", ""),
|
|
||||||
dim = not file_exists,
|
|
||||||
mandatory = file_exists and util.getFriendlySize(lfs.attributes(file_path, "size") or 0) or "",
|
|
||||||
select_enabled = file_exists,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
table.sort(list, function(v1,v2)
|
collections:saveSetting(coll_name, data)
|
||||||
return v1.order < v2.order
|
end
|
||||||
end)
|
end
|
||||||
return list
|
logger.dbg("ReadCollection: writing to collection file")
|
||||||
|
collections:flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:removeItemByPath(path, is_dir)
|
function ReadCollection:getFileCollectionName(file, collection_name)
|
||||||
local dir
|
file = FFIUtil.realpath(file) or file
|
||||||
local should_write = false
|
for coll_name, coll in pairs(self.coll) do
|
||||||
if is_dir then
|
if not collection_name or coll_name == collection_name then
|
||||||
path = path .. "/"
|
if coll[file] then
|
||||||
end
|
return coll_name, file
|
||||||
local coll = self:readAllCollection()
|
|
||||||
for i in pairs(coll) do
|
|
||||||
local single_collection = coll[i]
|
|
||||||
for item = #single_collection, 1, -1 do
|
|
||||||
if not is_dir and single_collection[item].file == path then
|
|
||||||
should_write = true
|
|
||||||
table.remove(single_collection, item)
|
|
||||||
elseif is_dir then
|
|
||||||
dir = util.splitFilePathName(single_collection[item].file)
|
|
||||||
if dir == path then
|
|
||||||
should_write = true
|
|
||||||
table.remove(single_collection, item)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
if should_write then
|
|
||||||
local collection = LuaSettings:open(collection_file)
|
|
||||||
collection.data = coll
|
|
||||||
collection:flush()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:updateItemByPath(old_path, new_path)
|
function ReadCollection:hasFile(file, collection_name)
|
||||||
local is_dir = false
|
local coll_name = self:getFileCollectionName(file, collection_name)
|
||||||
local dir, file
|
return coll_name and true or false
|
||||||
if lfs.attributes(new_path, "mode") == "directory" then
|
|
||||||
is_dir = true
|
|
||||||
old_path = old_path .. "/"
|
|
||||||
end
|
|
||||||
local should_write = false
|
|
||||||
local coll = self:readAllCollection()
|
|
||||||
for i, j in pairs(coll) do
|
|
||||||
for k, v in pairs(j) do
|
|
||||||
if not is_dir and v.file == old_path then
|
|
||||||
should_write = true
|
|
||||||
coll[i][k].file = new_path
|
|
||||||
elseif is_dir then
|
|
||||||
dir, file = util.splitFilePathName(v.file)
|
|
||||||
if dir == old_path then
|
|
||||||
should_write = true
|
|
||||||
coll[i][k].file = string.format("%s/%s", new_path, file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if should_write then
|
|
||||||
local collection = LuaSettings:open(collection_file)
|
|
||||||
collection.data = coll
|
|
||||||
collection:flush()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:removeItem(item, collection_name)
|
function ReadCollection:getCollectionMaxOrder(collection_name)
|
||||||
local coll = self:read(collection_name)
|
local max_order = 0
|
||||||
for k, v in pairs(coll) do
|
for _, item in pairs(self.coll[collection_name]) do
|
||||||
if v.file == item then
|
if max_order < item.order then
|
||||||
table.remove(coll, k)
|
max_order = item.order
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:writeCollection(coll, collection_name)
|
return max_order
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:writeCollection(coll_items, collection_name)
|
function ReadCollection:getOrderedCollection(collection_name)
|
||||||
local collection = LuaSettings:open(collection_file)
|
local ordered_coll = {}
|
||||||
collection:saveSetting(collection_name or DEFAULT_COLLECTION_NAME, coll_items)
|
for _, item in pairs(self.coll[collection_name]) do
|
||||||
collection:flush()
|
table.insert(ordered_coll, item)
|
||||||
|
end
|
||||||
|
table.sort(ordered_coll, function(v1, v2) return v1.order < v2.order end)
|
||||||
|
return ordered_coll
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:updateCollectionOrder(collection_name, ordered_coll)
|
||||||
|
local coll = self.coll[collection_name]
|
||||||
|
for i, item in ipairs(ordered_coll) do
|
||||||
|
coll[item.file].order = i
|
||||||
|
end
|
||||||
|
self:write(collection_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:addItem(file, collection_name)
|
function ReadCollection:addItem(file, collection_name)
|
||||||
local coll, coll_max_item = self:read(collection_name)
|
collection_name = collection_name or self.default_collection_name
|
||||||
local collection_item = {
|
local max_order = self:getCollectionMaxOrder(collection_name)
|
||||||
file = file,
|
local item = buildEntry(file, max_order + 1)
|
||||||
order = coll_max_item + 1,
|
self.coll[collection_name][item.file] = item
|
||||||
}
|
self:write(collection_name)
|
||||||
table.insert(coll, collection_item)
|
|
||||||
self:writeCollection(coll, collection_name)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReadCollection:checkItemExist(item, collection_name)
|
function ReadCollection:addItems(files, collection_name) -- files = { filepath = true, }
|
||||||
local coll = self:read(collection_name)
|
collection_name = collection_name or self.default_collection_name
|
||||||
for _, v in pairs(coll) do
|
local coll = self.coll[collection_name]
|
||||||
if v.file == item then
|
local max_order = self:getCollectionMaxOrder(collection_name)
|
||||||
|
local do_write
|
||||||
|
for file in pairs(files) do
|
||||||
|
if not self:hasFile(file) then
|
||||||
|
max_order = max_order + 1
|
||||||
|
local item = buildEntry(file, max_order)
|
||||||
|
coll[item.file] = item
|
||||||
|
do_write = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if do_write then
|
||||||
|
self:write(collection_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:removeItem(file, collection_name, no_write)
|
||||||
|
local coll_name, file_name = self:getFileCollectionName(file, collection_name)
|
||||||
|
if coll_name then
|
||||||
|
self.coll[coll_name][file_name] = nil
|
||||||
|
if not no_write then
|
||||||
|
self:write(coll_name)
|
||||||
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:removeItems(files) -- files = { filepath = true, }
|
||||||
|
local do_write
|
||||||
|
for file in pairs(files) do
|
||||||
|
if self:removeItem(file, nil, true) then
|
||||||
|
do_write = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if do_write then
|
||||||
|
self:write()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ReadCollection:removeItemsByPath(path)
|
||||||
|
local do_write
|
||||||
|
for coll_name, coll in pairs(self.coll) do
|
||||||
|
for file_name in pairs(coll) do
|
||||||
|
if util.stringStartsWith(file_name, path) then
|
||||||
|
self.coll[coll_name][file_name] = nil
|
||||||
|
do_write = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if do_write then
|
||||||
|
self:write()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:_updateItem(coll_name, file_name, new_filepath, new_path)
|
||||||
|
local coll = self.coll[coll_name]
|
||||||
|
local item_old = coll[file_name]
|
||||||
|
local order, mandatory = item_old.order, item_old.mandatory
|
||||||
|
new_filepath = new_filepath or new_path .. "/" .. item_old.text
|
||||||
|
coll[file_name] = nil
|
||||||
|
local item = buildEntry(new_filepath, order, mandatory) -- no lfs call
|
||||||
|
coll[item.file] = item
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:updateItem(file, new_filepath)
|
||||||
|
local coll_name, file_name = self:getFileCollectionName(file)
|
||||||
|
if coll_name then
|
||||||
|
self:_updateItem(coll_name, file_name, new_filepath)
|
||||||
|
self:write(coll_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:updateItems(files, new_path) -- files = { filepath = true, }
|
||||||
|
local do_write
|
||||||
|
for file in pairs(files) do
|
||||||
|
local coll_name, file_name = self:getFileCollectionName(file)
|
||||||
|
if coll_name then
|
||||||
|
self:_updateItem(coll_name, file_name, nil, new_path)
|
||||||
|
do_write = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if do_write then
|
||||||
|
self:write()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadCollection:updateItemsByPath(path, new_path)
|
||||||
|
local len = #path
|
||||||
|
local do_write
|
||||||
|
for coll_name, coll in pairs(self.coll) do
|
||||||
|
for file_name in pairs(coll) do
|
||||||
|
if file_name:sub(1, len) == path then
|
||||||
|
self:_updateItem(coll_name, file_name, new_path .. file_name:sub(len + 1))
|
||||||
|
do_write = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if do_write then
|
||||||
|
self:write()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ReadCollection:_read()
|
||||||
|
|
||||||
return ReadCollection
|
return ReadCollection
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ local util = require("util")
|
|||||||
local joinPath = ffiutil.joinPath
|
local joinPath = ffiutil.joinPath
|
||||||
local lfs = require("libs/libkoreader-lfs")
|
local lfs = require("libs/libkoreader-lfs")
|
||||||
local realpath = ffiutil.realpath
|
local realpath = ffiutil.realpath
|
||||||
|
local C_ = require("gettext").pgettext
|
||||||
|
|
||||||
local history_file = joinPath(DataStorage:getDataDir(), "history.lua")
|
local history_file = joinPath(DataStorage:getDataDir(), "history.lua")
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ local ReadHistory = {
|
|||||||
|
|
||||||
local function getMandatory(date_time)
|
local function getMandatory(date_time)
|
||||||
return G_reader_settings:isTrue("history_datetime_short")
|
return G_reader_settings:isTrue("history_datetime_short")
|
||||||
and datetime.secondsToDate(date_time):sub(3) or datetime.secondsToDateTime(date_time)
|
and os.date(C_("Date string", "%y-%m-%d"), date_time) or datetime.secondsToDateTime(date_time)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function buildEntry(input_time, input_file)
|
local function buildEntry(input_time, input_file)
|
||||||
@@ -181,23 +182,38 @@ function ReadHistory:getFileByDirectory(directory, recursive)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Updates the history list after renaming/moving a file.
|
--- Updates the history list after renaming/moving a file.
|
||||||
function ReadHistory:updateItemByPath(old_path, new_path)
|
function ReadHistory:updateItem(file, new_filepath)
|
||||||
local index = self:getIndexByFile(old_path)
|
local index = self:getIndexByFile(file)
|
||||||
if index then
|
if index then
|
||||||
self.hist[index].file = new_path
|
local item = self.hist[index]
|
||||||
self.hist[index].text = new_path:gsub(".*/", "")
|
item.file = new_filepath
|
||||||
|
item.text = new_filepath:gsub(".*/", "")
|
||||||
|
self:_flush()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReadHistory:updateItems(files, new_path) -- files = { filepath = true, }
|
||||||
|
local history_updated
|
||||||
|
for file in pairs(files) do
|
||||||
|
local index = self:getIndexByFile(file)
|
||||||
|
if index then
|
||||||
|
local item = self.hist[index]
|
||||||
|
item.file = new_path .. "/" .. item.text
|
||||||
|
history_updated = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if history_updated then
|
||||||
self:_flush()
|
self:_flush()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Updates the history list after renaming/moving a folder.
|
--- Updates the history list after renaming/moving a folder.
|
||||||
function ReadHistory:updateItemsByPath(old_path, new_path)
|
function ReadHistory:updateItemsByPath(old_path, new_path)
|
||||||
old_path = "^"..old_path
|
local len = #old_path
|
||||||
local history_updated
|
local history_updated
|
||||||
for i, v in ipairs(self.hist) do
|
for i, v in ipairs(self.hist) do
|
||||||
local file, count = v.file:gsub(old_path, new_path)
|
if v.file:sub(1, len) == old_path then
|
||||||
if count == 1 then
|
self.hist[i].file = new_path .. v.file:sub(len + 1)
|
||||||
self.hist[i].file = file
|
|
||||||
history_updated = true
|
history_updated = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -248,6 +264,24 @@ function ReadHistory:folderDeleted(path)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ReadHistory:removeItems(files) -- files = { filepath = true, }
|
||||||
|
local history_updated
|
||||||
|
for file in pairs(files) do
|
||||||
|
local index = self:getIndexByFile(file)
|
||||||
|
if index then
|
||||||
|
self:fileDeleted(index)
|
||||||
|
history_updated = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if history_updated then
|
||||||
|
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
||||||
|
self:_flush()
|
||||||
|
else
|
||||||
|
self:ensureLastFile()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Removes the history item if the document settings has been reset.
|
--- Removes the history item if the document settings has been reset.
|
||||||
function ReadHistory:fileSettingsPurged(path)
|
function ReadHistory:fileSettingsPurged(path)
|
||||||
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe("FileManager module", function()
|
|||||||
assert.Equals(w.text, "File not found:\n"..tmp_fn)
|
assert.Equals(w.text, "File not found:\n"..tmp_fn)
|
||||||
end
|
end
|
||||||
assert.is_nil(lfs.attributes(tmp_fn))
|
assert.is_nil(lfs.attributes(tmp_fn))
|
||||||
filemanager:deleteFile(tmp_fn, true)
|
filemanager:showDeleteFileDialog(tmp_fn)
|
||||||
UIManager.show = old_show
|
UIManager.show = old_show
|
||||||
filemanager:onClose()
|
filemanager:onClose()
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user