mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
File browser: add Folder Menu (#10275)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
local BD = require("ui/bidi")
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
||||
local CheckButton = require("ui/widget/checkbutton")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
@@ -9,7 +10,6 @@ local DocSettings = require("docsettings")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local Event = require("ui/event")
|
||||
local FileChooser = require("ui/widget/filechooser")
|
||||
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
||||
local FileManagerCollection = require("apps/filemanager/filemanagercollection")
|
||||
local FileManagerConverter = require("apps/filemanager/filemanagerconverter")
|
||||
local FileManagerFileSearcher = require("apps/filemanager/filemanagerfilesearcher")
|
||||
@@ -52,7 +52,6 @@ local FileManager = InputContainer:extend{
|
||||
|
||||
mv_bin = Device:isAndroid() and "/system/bin/mv" or "/bin/mv",
|
||||
cp_bin = Device:isAndroid() and "/system/bin/cp" or "/bin/cp",
|
||||
mkdir_bin = Device:isAndroid() and "/system/bin/mkdir" or "/bin/mkdir",
|
||||
}
|
||||
|
||||
function FileManager:onSetRotationMode(rotation)
|
||||
@@ -120,7 +119,7 @@ function FileManager:setupLayout()
|
||||
button_padding = Screen:scaleBySize(5),
|
||||
left_icon = "home",
|
||||
left_icon_size_ratio = 1,
|
||||
left_icon_tap_callback = function() self:goHome() end,
|
||||
left_icon_tap_callback = function() self:onShowFolderMenu() end,
|
||||
left_icon_hold_callback = false, -- propagate long-press to dispatcher
|
||||
right_icon = "plus",
|
||||
right_icon_size_ratio = 1,
|
||||
@@ -135,7 +134,6 @@ function FileManager:setupLayout()
|
||||
path = self.root_path,
|
||||
focused_path = self.focused_file,
|
||||
show_parent = self.show_parent,
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight() - self.title_bar:getHeight(),
|
||||
is_popout = false,
|
||||
is_borderless = true,
|
||||
@@ -254,6 +252,9 @@ function FileManager:setupLayout()
|
||||
}
|
||||
|
||||
if is_file then
|
||||
local function close_dialog_callback()
|
||||
UIManager:close(self.file_dialog)
|
||||
end
|
||||
local function status_button_callback()
|
||||
UIManager:close(self.file_dialog)
|
||||
self:refreshPath() -- sidecar folder may be created/deleted
|
||||
@@ -305,39 +306,15 @@ function FileManager:setupLayout()
|
||||
self:showSetProviderButtons(file, one_time_providers)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Book information"),
|
||||
id = "book_information", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.file_dialog)
|
||||
FileManagerBookInfo:show(file)
|
||||
end,
|
||||
},
|
||||
filemanagerutil.genBookInformationButton(file, close_dialog_callback),
|
||||
})
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = _("Book cover"),
|
||||
id = "book_cover", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.file_dialog)
|
||||
FileManagerBookInfo:onShowBookCover(file)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Book description"),
|
||||
id = "book_description", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.file_dialog)
|
||||
FileManagerBookInfo:onShowBookDescription(nil, file)
|
||||
end,
|
||||
},
|
||||
filemanagerutil.genBookCoverButton(file, close_dialog_callback),
|
||||
filemanagerutil.genBookDescriptionButton(file, close_dialog_callback),
|
||||
})
|
||||
if Device:canExecuteScript(file) then
|
||||
local function button_callback()
|
||||
UIManager:close(self.file_dialog)
|
||||
end
|
||||
table.insert(buttons, {
|
||||
filemanagerutil.genExecuteScriptButton(file, button_callback)
|
||||
filemanagerutil.genExecuteScriptButton(file, close_dialog_callback),
|
||||
})
|
||||
end
|
||||
if FileManagerConverter:isSupported(file) then
|
||||
@@ -348,7 +325,7 @@ function FileManager:setupLayout()
|
||||
UIManager:close(self.file_dialog)
|
||||
FileManagerConverter:showConvertButtons(file, self)
|
||||
end,
|
||||
}
|
||||
},
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -361,7 +338,7 @@ function FileManager:setupLayout()
|
||||
UIManager:close(self.file_dialog)
|
||||
file_manager:setHome(BaseUtil.realpath(file))
|
||||
end
|
||||
}
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
@@ -850,7 +827,7 @@ end
|
||||
function FileManager:openRandomFile(dir)
|
||||
local random_file = DocumentRegistry:getRandomFile(dir, false)
|
||||
if random_file then
|
||||
UIManager:show(MultiConfirmBox:new {
|
||||
UIManager:show(MultiConfirmBox:new{
|
||||
text = T(_("Do you want to open %1?"), BD.filename(BaseUtil.basename(random_file))),
|
||||
choice1_text = _("Open"),
|
||||
choice1_callback = function()
|
||||
@@ -864,7 +841,7 @@ function FileManager:openRandomFile(dir)
|
||||
end,
|
||||
})
|
||||
else
|
||||
UIManager:show(InfoMessage:new {
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("File not found"),
|
||||
})
|
||||
end
|
||||
@@ -895,7 +872,7 @@ function FileManager:pasteHere(file)
|
||||
end
|
||||
return true
|
||||
else
|
||||
UIManager:show(InfoMessage:new {
|
||||
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",
|
||||
})
|
||||
@@ -911,7 +888,7 @@ function FileManager:pasteHere(file)
|
||||
ReadCollection:updateItemByPath(orig_file, dest_file)
|
||||
return true
|
||||
else
|
||||
UIManager:show(InfoMessage:new {
|
||||
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",
|
||||
})
|
||||
@@ -928,7 +905,7 @@ function FileManager:pasteHere(file)
|
||||
|
||||
local mode = lfs.attributes(dest_file, "mode")
|
||||
if mode 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))
|
||||
or T(_("Folder already exists:\n%1\nOverwrite folder?"), BD.directory(orig_name)),
|
||||
ok_text = _("Overwrite"),
|
||||
@@ -1099,7 +1076,7 @@ function FileManager:renameFile(file, basename, is_file)
|
||||
else
|
||||
text = T(_("File already exists:\n%1\nFolder cannot be renamed."), BD.filename(basename))
|
||||
end
|
||||
UIManager:show(InfoMessage:new {
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = text,
|
||||
icon = "notice-warning",
|
||||
})
|
||||
@@ -1111,7 +1088,7 @@ function FileManager:renameFile(file, basename, is_file)
|
||||
text = T(_("Folder already exists:\n%1\nMove the folder inside it?"), BD.directory(basename))
|
||||
ok_text = _("Move")
|
||||
end
|
||||
UIManager:show(ConfirmBox:new {
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = text,
|
||||
ok_text = ok_text,
|
||||
ok_callback = function()
|
||||
@@ -1201,4 +1178,70 @@ function FileManager:onRefreshContent()
|
||||
self:onRefresh()
|
||||
end
|
||||
|
||||
function FileManager:onShowFolderMenu()
|
||||
local button_dialog
|
||||
local function genButton(button_text, button_path)
|
||||
return {{
|
||||
text = button_text,
|
||||
align = "left",
|
||||
font_face = "smallinfofont",
|
||||
font_size = 22,
|
||||
font_bold = false,
|
||||
avoid_text_truncation = false,
|
||||
callback = function()
|
||||
UIManager:close(button_dialog)
|
||||
self.file_chooser:changeToPath(button_path)
|
||||
end,
|
||||
hold_callback = function()
|
||||
return true -- do not move the menu
|
||||
end,
|
||||
}}
|
||||
end
|
||||
|
||||
local home_dir = G_reader_settings:readSetting("home_dir") or filemanagerutil.getDefaultDir()
|
||||
local home_dir_shortened = G_reader_settings:nilOrTrue("shorten_home_dir")
|
||||
local home_dir_not_locked = G_reader_settings:nilOrFalse("lock_home_folder")
|
||||
local home_dir_suffix = " (" .. _("Home") .. ")"
|
||||
local buttons = {}
|
||||
-- root folder
|
||||
local text
|
||||
local path = "/"
|
||||
local is_home = path == home_dir
|
||||
local home_found = is_home or home_dir_not_locked
|
||||
if home_found then
|
||||
text = path
|
||||
if is_home and home_dir_shortened then
|
||||
text = text .. home_dir_suffix
|
||||
end
|
||||
table.insert(buttons, genButton(text, path))
|
||||
end
|
||||
-- other folders
|
||||
local indent = ""
|
||||
for part in self.file_chooser.path:gmatch("([^/]+)") do
|
||||
text = (#buttons == 0 and path or indent .. "└ ") .. part
|
||||
path = path .. part .. "/"
|
||||
is_home = path == home_dir or path == home_dir .. "/"
|
||||
if not home_found and is_home then
|
||||
home_found = true
|
||||
end
|
||||
if home_found then
|
||||
if is_home and home_dir_shortened then
|
||||
text = text .. home_dir_suffix
|
||||
end
|
||||
table.insert(buttons, genButton(text, path))
|
||||
indent = indent .. " "
|
||||
end
|
||||
end
|
||||
|
||||
button_dialog = ButtonDialog:new{
|
||||
width = math.floor(Screen:getWidth() * 0.9),
|
||||
shrink_unneeded_width = true,
|
||||
buttons = buttons,
|
||||
anchor = function()
|
||||
return self.title_bar.left_button.image.dimen
|
||||
end,
|
||||
}
|
||||
UIManager:show(button_dialog)
|
||||
end
|
||||
|
||||
return FileManager
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
||||
local Device = require("device")
|
||||
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local ReadCollection = require("readcollection")
|
||||
local UIManager = require("ui/uimanager")
|
||||
@@ -36,8 +35,15 @@ function FileManagerCollection:updateItemTable()
|
||||
ReadCollection:prepareList(self.coll_menu.collection), select_number)
|
||||
end
|
||||
|
||||
function FileManagerCollection:onMenuChoice(item)
|
||||
require("apps/reader/readerui"):showReader(item.file)
|
||||
end
|
||||
|
||||
function FileManagerCollection:onMenuHold(item)
|
||||
self.collfile_dialog = nil
|
||||
local function close_dialog_callback()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
end
|
||||
local function status_button_callback()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
self._manager:updateItemTable()
|
||||
@@ -89,37 +95,17 @@ function FileManagerCollection:onMenuHold(item)
|
||||
UIManager:show(sort_item)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Book information"),
|
||||
id = "book_information", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
FileManagerBookInfo:show(item.file)
|
||||
end,
|
||||
},
|
||||
filemanagerutil.genBookInformationButton(item.file, close_dialog_callback, item.dim),
|
||||
})
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = _("Book cover"),
|
||||
id = "book_cover", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
FileManagerBookInfo:onShowBookCover(item.file)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Book description"),
|
||||
id = "book_description", -- used by covermenu
|
||||
callback = function()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
FileManagerBookInfo:onShowBookDescription(nil, item.file)
|
||||
end,
|
||||
},
|
||||
filemanagerutil.genBookCoverButton(item.file, close_dialog_callback, item.dim),
|
||||
filemanagerutil.genBookDescriptionButton(item.file, close_dialog_callback, item.dim),
|
||||
})
|
||||
|
||||
if Device:canExecuteScript(item.file) then
|
||||
local function button_callback()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
self.coll_menu.close_callback()
|
||||
end
|
||||
table.insert(buttons, {
|
||||
filemanagerutil.genExecuteScriptButton(item.file, button_callback)
|
||||
@@ -153,11 +139,10 @@ end
|
||||
function FileManagerCollection:onShowColl(collection)
|
||||
self.coll_menu = Menu:new{
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
||||
is_borderless = true,
|
||||
is_popout = false,
|
||||
onMenuChoice = self.onMenuChoice,
|
||||
onMenuHold = self.onMenuHold,
|
||||
onSetRotationMode = self.MenuSetRotationModeHandler,
|
||||
_manager = self,
|
||||
|
||||
@@ -83,6 +83,9 @@ end
|
||||
|
||||
function FileManagerHistory:onMenuHold(item)
|
||||
self.histfile_dialog = nil
|
||||
local function close_dialog_callback()
|
||||
UIManager:close(self.histfile_dialog)
|
||||
end
|
||||
local function status_button_callback()
|
||||
UIManager:close(self.histfile_dialog)
|
||||
if self._manager.filter ~= "all" then
|
||||
@@ -125,11 +128,11 @@ function FileManagerHistory:onMenuHold(item)
|
||||
FileManager:showDeleteFileDialog(item.file, post_delete_callback)
|
||||
end,
|
||||
},
|
||||
filemanagerutil.genBookInformationButton(item.file, self.histfile_dialog, item.dim),
|
||||
filemanagerutil.genBookInformationButton(item.file, close_dialog_callback, item.dim),
|
||||
})
|
||||
table.insert(buttons, {
|
||||
filemanagerutil.genBookCoverButton(item.file, self.histfile_dialog, item.dim),
|
||||
filemanagerutil.genBookDescriptionButton(item.file, self.histfile_dialog, item.dim),
|
||||
filemanagerutil.genBookCoverButton(item.file, close_dialog_callback, item.dim),
|
||||
filemanagerutil.genBookDescriptionButton(item.file, close_dialog_callback, item.dim),
|
||||
})
|
||||
|
||||
self.histfile_dialog = ButtonDialogTitle:new{
|
||||
@@ -226,7 +229,7 @@ function FileManagerHistory:showHistDialog()
|
||||
{
|
||||
text = _("Clear history of deleted files"),
|
||||
callback = function()
|
||||
UIManager:show(ConfirmBox:new{
|
||||
local confirmbox = ConfirmBox:new{
|
||||
text = _("Clear history of deleted files?"),
|
||||
ok_text = _("Clear"),
|
||||
ok_callback = function()
|
||||
@@ -234,7 +237,8 @@ function FileManagerHistory:showHistDialog()
|
||||
require("readhistory"):clearMissing()
|
||||
self:updateItemTable()
|
||||
end,
|
||||
})
|
||||
}
|
||||
UIManager:show(confirmbox)
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -158,42 +158,42 @@ function filemanagerutil.genResetSettingsButton(file, caller_callback, button_di
|
||||
}
|
||||
end
|
||||
|
||||
function filemanagerutil.genBookInformationButton(file, dialog, button_disabled)
|
||||
function filemanagerutil.genBookInformationButton(file, caller_callback, button_disabled)
|
||||
return {
|
||||
text = _("Book information"),
|
||||
id = "book_information", -- used by covermenu
|
||||
enabled = not button_disabled,
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
caller_callback()
|
||||
require("apps/filemanager/filemanagerbookinfo"):show(file)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function filemanagerutil.genBookDescriptionButton(file, dialog, button_disabled)
|
||||
return {
|
||||
text = _("Book description"),
|
||||
id = "book_description", -- used by covermenu
|
||||
enabled = not button_disabled,
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
require("apps/filemanager/filemanagerbookinfo"):onShowBookDescription(nil, file)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function filemanagerutil.genBookCoverButton(file, dialog, button_disabled)
|
||||
function filemanagerutil.genBookCoverButton(file, caller_callback, button_disabled)
|
||||
return {
|
||||
text = _("Book cover"),
|
||||
id = "book_cover", -- used by covermenu
|
||||
enabled = not button_disabled,
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
caller_callback()
|
||||
require("apps/filemanager/filemanagerbookinfo"):onShowBookCover(file)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function filemanagerutil.genBookDescriptionButton(file, caller_callback, button_disabled)
|
||||
return {
|
||||
text = _("Book description"),
|
||||
id = "book_description", -- used by covermenu
|
||||
enabled = not button_disabled,
|
||||
callback = function()
|
||||
caller_callback()
|
||||
require("apps/filemanager/filemanagerbookinfo"):onShowBookDescription(nil, file)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
-- Generate "Execute script" file dialog button
|
||||
function filemanagerutil.genExecuteScriptButton(file, caller_callback)
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
|
||||
@@ -14,7 +14,6 @@ function ReadCollection:read(collection_name)
|
||||
local collections = LuaSettings:open(collection_file)
|
||||
local coll = collections:readSetting(collection_name) or {}
|
||||
local coll_max_item = 0
|
||||
|
||||
for _, v in pairs(coll) do
|
||||
if v.order > coll_max_item then
|
||||
coll_max_item = v.order
|
||||
@@ -36,17 +35,15 @@ function ReadCollection:prepareList(collection_name)
|
||||
local data = self:read(collection_name)
|
||||
local list = {}
|
||||
for _, v in pairs(data) do
|
||||
local file_exists = lfs.attributes(v.file, "mode") == "file"
|
||||
local file_path = FFIUtil.realpath(v.file) or v.file -- keep orig file path of deleted files
|
||||
local file_exists = lfs.attributes(file_path, "mode") == "file"
|
||||
table.insert(list, {
|
||||
order = v.order,
|
||||
file = file_path,
|
||||
text = v.file:gsub(".*/", ""),
|
||||
file = FFIUtil.realpath(v.file) or v.file, -- keep orig file path of deleted files
|
||||
dim = not file_exists, -- "dim", as expected by Menu
|
||||
mandatory = file_exists and util.getFriendlySize(lfs.attributes(v.file, "size") or 0),
|
||||
callback = function()
|
||||
local ReaderUI = require("apps/reader/readerui")
|
||||
ReaderUI:showReader(v.file)
|
||||
end
|
||||
dim = not file_exists,
|
||||
mandatory = file_exists and util.getFriendlySize(lfs.attributes(file_path, "size") or 0),
|
||||
select_enabled = file_exists,
|
||||
})
|
||||
end
|
||||
table.sort(list, function(v1,v2)
|
||||
@@ -62,7 +59,7 @@ function ReadCollection:removeItemByPath(path, is_dir)
|
||||
path = path .. "/"
|
||||
end
|
||||
local coll = self:readAllCollection()
|
||||
for i, _ in pairs(coll) do
|
||||
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
|
||||
@@ -126,19 +123,16 @@ function ReadCollection:removeItem(item, collection_name)
|
||||
end
|
||||
|
||||
function ReadCollection:writeCollection(coll_items, collection_name)
|
||||
if not collection_name then collection_name = DEFAULT_COLLECTION_NAME end
|
||||
local collection = LuaSettings:open(collection_file)
|
||||
collection:saveSetting(collection_name, coll_items)
|
||||
collection:saveSetting(collection_name or DEFAULT_COLLECTION_NAME, coll_items)
|
||||
collection:flush()
|
||||
end
|
||||
|
||||
function ReadCollection:addItem(file, collection_name)
|
||||
local coll, coll_max_item = self:read(collection_name)
|
||||
coll_max_item = coll_max_item + 1
|
||||
local collection_item =
|
||||
{
|
||||
local collection_item = {
|
||||
file = file,
|
||||
order = coll_max_item
|
||||
order = coll_max_item + 1,
|
||||
}
|
||||
table.insert(coll, collection_item)
|
||||
self:writeCollection(coll, collection_name)
|
||||
@@ -151,8 +145,6 @@ function ReadCollection:checkItemExist(item, collection_name)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return ReadCollection
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ function ButtonTable:init()
|
||||
padding = Size.padding.buttontable, -- a bit taller than standalone buttons, for easier tap
|
||||
padding_h = btn_entry.align == "left" and Size.padding.large or 0,
|
||||
-- allow text to take more of the horizontal space if centered
|
||||
avoid_text_truncation = btn_entry.avoid_text_truncation,
|
||||
text_font_face = btn_entry.font_face,
|
||||
text_font_size = btn_entry.font_size,
|
||||
text_font_bold = btn_entry.font_bold,
|
||||
|
||||
Reference in New Issue
Block a user