File browser: add Folder Menu (#10275)

reviewable/pr10278/r1
hius07 1 year ago committed by GitHub
parent 983e083a0b
commit 59a0139a60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,6 @@
local BD = require("ui/bidi") local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer") local Blitbuffer = require("ffi/blitbuffer")
local ButtonDialog = require("ui/widget/buttondialog")
local ButtonDialogTitle = require("ui/widget/buttondialogtitle") local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local CheckButton = require("ui/widget/checkbutton") local CheckButton = require("ui/widget/checkbutton")
local ConfirmBox = require("ui/widget/confirmbox") local ConfirmBox = require("ui/widget/confirmbox")
@ -9,7 +10,6 @@ local DocSettings = require("docsettings")
local DocumentRegistry = require("document/documentregistry") local DocumentRegistry = require("document/documentregistry")
local Event = require("ui/event") local Event = require("ui/event")
local FileChooser = require("ui/widget/filechooser") local FileChooser = require("ui/widget/filechooser")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local FileManagerCollection = require("apps/filemanager/filemanagercollection") local FileManagerCollection = require("apps/filemanager/filemanagercollection")
local FileManagerConverter = require("apps/filemanager/filemanagerconverter") local FileManagerConverter = require("apps/filemanager/filemanagerconverter")
local FileManagerFileSearcher = require("apps/filemanager/filemanagerfilesearcher") 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", mv_bin = Device:isAndroid() and "/system/bin/mv" or "/bin/mv",
cp_bin = Device:isAndroid() and "/system/bin/cp" or "/bin/cp", 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) function FileManager:onSetRotationMode(rotation)
@ -120,7 +119,7 @@ function FileManager:setupLayout()
button_padding = Screen:scaleBySize(5), button_padding = Screen:scaleBySize(5),
left_icon = "home", left_icon = "home",
left_icon_size_ratio = 1, 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 left_icon_hold_callback = false, -- propagate long-press to dispatcher
right_icon = "plus", right_icon = "plus",
right_icon_size_ratio = 1, right_icon_size_ratio = 1,
@ -135,7 +134,6 @@ function FileManager:setupLayout()
path = self.root_path, path = self.root_path,
focused_path = self.focused_file, focused_path = self.focused_file,
show_parent = self.show_parent, show_parent = self.show_parent,
width = Screen:getWidth(),
height = Screen:getHeight() - self.title_bar:getHeight(), height = Screen:getHeight() - self.title_bar:getHeight(),
is_popout = false, is_popout = false,
is_borderless = true, is_borderless = true,
@ -254,6 +252,9 @@ function FileManager:setupLayout()
} }
if is_file then if is_file then
local function close_dialog_callback()
UIManager:close(self.file_dialog)
end
local function status_button_callback() local function status_button_callback()
UIManager:close(self.file_dialog) UIManager:close(self.file_dialog)
self:refreshPath() -- sidecar folder may be created/deleted self:refreshPath() -- sidecar folder may be created/deleted
@ -305,39 +306,15 @@ function FileManager:setupLayout()
self:showSetProviderButtons(file, one_time_providers) self:showSetProviderButtons(file, one_time_providers)
end, end,
}, },
{ filemanagerutil.genBookInformationButton(file, close_dialog_callback),
text = _("Book information"),
id = "book_information", -- used by covermenu
callback = function()
UIManager:close(self.file_dialog)
FileManagerBookInfo:show(file)
end,
},
}) })
table.insert(buttons, { table.insert(buttons, {
{ filemanagerutil.genBookCoverButton(file, close_dialog_callback),
text = _("Book cover"), filemanagerutil.genBookDescriptionButton(file, close_dialog_callback),
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,
},
}) })
if Device:canExecuteScript(file) then if Device:canExecuteScript(file) then
local function button_callback()
UIManager:close(self.file_dialog)
end
table.insert(buttons, { table.insert(buttons, {
filemanagerutil.genExecuteScriptButton(file, button_callback) filemanagerutil.genExecuteScriptButton(file, close_dialog_callback),
}) })
end end
if FileManagerConverter:isSupported(file) then if FileManagerConverter:isSupported(file) then
@ -348,7 +325,7 @@ function FileManager:setupLayout()
UIManager:close(self.file_dialog) UIManager:close(self.file_dialog)
FileManagerConverter:showConvertButtons(file, self) FileManagerConverter:showConvertButtons(file, self)
end, end,
} },
}) })
end end
end end
@ -361,7 +338,7 @@ function FileManager:setupLayout()
UIManager:close(self.file_dialog) UIManager:close(self.file_dialog)
file_manager:setHome(BaseUtil.realpath(file)) file_manager:setHome(BaseUtil.realpath(file))
end end
} },
}) })
end end
@ -850,7 +827,7 @@ end
function FileManager:openRandomFile(dir) function FileManager:openRandomFile(dir)
local random_file = DocumentRegistry:getRandomFile(dir, false) local random_file = DocumentRegistry:getRandomFile(dir, false)
if random_file then 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))), text = T(_("Do you want to open %1?"), BD.filename(BaseUtil.basename(random_file))),
choice1_text = _("Open"), choice1_text = _("Open"),
choice1_callback = function() choice1_callback = function()
@ -864,7 +841,7 @@ function FileManager:openRandomFile(dir)
end, end,
}) })
else else
UIManager:show(InfoMessage:new { UIManager:show(InfoMessage:new{
text = _("File not found"), text = _("File not found"),
}) })
end end
@ -895,7 +872,7 @@ function FileManager:pasteHere(file)
end end
return true return true
else 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)), text = T(_("Failed to copy:\n%1\nto:\n%2"), BD.filepath(orig_name), BD.dirpath(dest_path)),
icon = "notice-warning", icon = "notice-warning",
}) })
@ -911,7 +888,7 @@ function FileManager:pasteHere(file)
ReadCollection:updateItemByPath(orig_file, dest_file) ReadCollection:updateItemByPath(orig_file, dest_file)
return true return true
else 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)), text = T(_("Failed to move:\n%1\nto:\n%2"), BD.filepath(orig_name), BD.dirpath(dest_path)),
icon = "notice-warning", icon = "notice-warning",
}) })
@ -928,7 +905,7 @@ function FileManager:pasteHere(file)
local mode = lfs.attributes(dest_file, "mode") local mode = lfs.attributes(dest_file, "mode")
if mode then 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)) 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)), or T(_("Folder already exists:\n%1\nOverwrite folder?"), BD.directory(orig_name)),
ok_text = _("Overwrite"), ok_text = _("Overwrite"),
@ -1099,7 +1076,7 @@ function FileManager:renameFile(file, basename, is_file)
else else
text = T(_("File already exists:\n%1\nFolder cannot be renamed."), BD.filename(basename)) text = T(_("File already exists:\n%1\nFolder cannot be renamed."), BD.filename(basename))
end end
UIManager:show(InfoMessage:new { UIManager:show(InfoMessage:new{
text = text, text = text,
icon = "notice-warning", 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)) text = T(_("Folder already exists:\n%1\nMove the folder inside it?"), BD.directory(basename))
ok_text = _("Move") ok_text = _("Move")
end end
UIManager:show(ConfirmBox:new { UIManager:show(ConfirmBox:new{
text = text, text = text,
ok_text = ok_text, ok_text = ok_text,
ok_callback = function() ok_callback = function()
@ -1201,4 +1178,70 @@ function FileManager:onRefreshContent()
self:onRefresh() self:onRefresh()
end 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 return FileManager

@ -1,6 +1,5 @@
local ButtonDialogTitle = require("ui/widget/buttondialogtitle") local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local Device = require("device") local Device = require("device")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local Menu = require("ui/widget/menu") local Menu = require("ui/widget/menu")
local ReadCollection = require("readcollection") local ReadCollection = require("readcollection")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
@ -36,8 +35,15 @@ function FileManagerCollection:updateItemTable()
ReadCollection:prepareList(self.coll_menu.collection), select_number) ReadCollection:prepareList(self.coll_menu.collection), select_number)
end end
function FileManagerCollection:onMenuChoice(item)
require("apps/reader/readerui"):showReader(item.file)
end
function FileManagerCollection:onMenuHold(item) function FileManagerCollection:onMenuHold(item)
self.collfile_dialog = nil self.collfile_dialog = nil
local function close_dialog_callback()
UIManager:close(self.collfile_dialog)
end
local function status_button_callback() local function status_button_callback()
UIManager:close(self.collfile_dialog) UIManager:close(self.collfile_dialog)
self._manager:updateItemTable() self._manager:updateItemTable()
@ -89,37 +95,17 @@ function FileManagerCollection:onMenuHold(item)
UIManager:show(sort_item) UIManager:show(sort_item)
end, end,
}, },
{ filemanagerutil.genBookInformationButton(item.file, close_dialog_callback, item.dim),
text = _("Book information"),
id = "book_information", -- used by covermenu
callback = function()
UIManager:close(self.collfile_dialog)
FileManagerBookInfo:show(item.file)
end,
},
}) })
table.insert(buttons, { table.insert(buttons, {
{ filemanagerutil.genBookCoverButton(item.file, close_dialog_callback, item.dim),
text = _("Book cover"), filemanagerutil.genBookDescriptionButton(item.file, close_dialog_callback, item.dim),
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,
},
}) })
if Device:canExecuteScript(item.file) then if Device:canExecuteScript(item.file) then
local function button_callback() local function button_callback()
UIManager:close(self.collfile_dialog) UIManager:close(self.collfile_dialog)
self.coll_menu.close_callback()
end end
table.insert(buttons, { table.insert(buttons, {
filemanagerutil.genExecuteScriptButton(item.file, button_callback) filemanagerutil.genExecuteScriptButton(item.file, button_callback)
@ -153,11 +139,10 @@ end
function FileManagerCollection:onShowColl(collection) function FileManagerCollection:onShowColl(collection)
self.coll_menu = Menu:new{ self.coll_menu = Menu:new{
ui = self.ui, ui = self.ui,
width = Screen:getWidth(),
height = Screen:getHeight(),
covers_fullscreen = true, -- hint for UIManager:_repaint() covers_fullscreen = true, -- hint for UIManager:_repaint()
is_borderless = true, is_borderless = true,
is_popout = false, is_popout = false,
onMenuChoice = self.onMenuChoice,
onMenuHold = self.onMenuHold, onMenuHold = self.onMenuHold,
onSetRotationMode = self.MenuSetRotationModeHandler, onSetRotationMode = self.MenuSetRotationModeHandler,
_manager = self, _manager = self,

@ -83,6 +83,9 @@ end
function FileManagerHistory:onMenuHold(item) function FileManagerHistory:onMenuHold(item)
self.histfile_dialog = nil self.histfile_dialog = nil
local function close_dialog_callback()
UIManager:close(self.histfile_dialog)
end
local function status_button_callback() local function status_button_callback()
UIManager:close(self.histfile_dialog) UIManager:close(self.histfile_dialog)
if self._manager.filter ~= "all" then if self._manager.filter ~= "all" then
@ -125,11 +128,11 @@ function FileManagerHistory:onMenuHold(item)
FileManager:showDeleteFileDialog(item.file, post_delete_callback) FileManager:showDeleteFileDialog(item.file, post_delete_callback)
end, end,
}, },
filemanagerutil.genBookInformationButton(item.file, self.histfile_dialog, item.dim), filemanagerutil.genBookInformationButton(item.file, close_dialog_callback, item.dim),
}) })
table.insert(buttons, { table.insert(buttons, {
filemanagerutil.genBookCoverButton(item.file, self.histfile_dialog, item.dim), filemanagerutil.genBookCoverButton(item.file, close_dialog_callback, item.dim),
filemanagerutil.genBookDescriptionButton(item.file, self.histfile_dialog, item.dim), filemanagerutil.genBookDescriptionButton(item.file, close_dialog_callback, item.dim),
}) })
self.histfile_dialog = ButtonDialogTitle:new{ self.histfile_dialog = ButtonDialogTitle:new{
@ -226,7 +229,7 @@ function FileManagerHistory:showHistDialog()
{ {
text = _("Clear history of deleted files"), text = _("Clear history of deleted files"),
callback = function() callback = function()
UIManager:show(ConfirmBox:new{ local confirmbox = ConfirmBox:new{
text = _("Clear history of deleted files?"), text = _("Clear history of deleted files?"),
ok_text = _("Clear"), ok_text = _("Clear"),
ok_callback = function() ok_callback = function()
@ -234,7 +237,8 @@ function FileManagerHistory:showHistDialog()
require("readhistory"):clearMissing() require("readhistory"):clearMissing()
self:updateItemTable() self:updateItemTable()
end, end,
}) }
UIManager:show(confirmbox)
end, end,
}, },
}) })

@ -158,38 +158,38 @@ function filemanagerutil.genResetSettingsButton(file, caller_callback, button_di
} }
end end
function filemanagerutil.genBookInformationButton(file, dialog, button_disabled) function filemanagerutil.genBookInformationButton(file, caller_callback, button_disabled)
return { return {
text = _("Book information"), text = _("Book information"),
id = "book_information", -- used by covermenu id = "book_information", -- used by covermenu
enabled = not button_disabled, enabled = not button_disabled,
callback = function() callback = function()
UIManager:close(dialog) caller_callback()
require("apps/filemanager/filemanagerbookinfo"):show(file) require("apps/filemanager/filemanagerbookinfo"):show(file)
end, end,
} }
end end
function filemanagerutil.genBookDescriptionButton(file, dialog, button_disabled) function filemanagerutil.genBookCoverButton(file, caller_callback, button_disabled)
return { return {
text = _("Book description"), text = _("Book cover"),
id = "book_description", -- used by covermenu id = "book_cover", -- used by covermenu
enabled = not button_disabled, enabled = not button_disabled,
callback = function() callback = function()
UIManager:close(dialog) caller_callback()
require("apps/filemanager/filemanagerbookinfo"):onShowBookDescription(nil, file) require("apps/filemanager/filemanagerbookinfo"):onShowBookCover(file)
end, end,
} }
end end
function filemanagerutil.genBookCoverButton(file, dialog, button_disabled) function filemanagerutil.genBookDescriptionButton(file, caller_callback, button_disabled)
return { return {
text = _("Book cover"), text = _("Book description"),
id = "book_cover", -- used by covermenu id = "book_description", -- used by covermenu
enabled = not button_disabled, enabled = not button_disabled,
callback = function() callback = function()
UIManager:close(dialog) caller_callback()
require("apps/filemanager/filemanagerbookinfo"):onShowBookCover(file) require("apps/filemanager/filemanagerbookinfo"):onShowBookDescription(nil, file)
end, end,
} }
end end

@ -14,7 +14,6 @@ function ReadCollection:read(collection_name)
local collections = LuaSettings:open(collection_file) local collections = LuaSettings:open(collection_file)
local coll = collections:readSetting(collection_name) or {} local coll = collections:readSetting(collection_name) or {}
local coll_max_item = 0 local coll_max_item = 0
for _, v in pairs(coll) do for _, v in pairs(coll) do
if v.order > coll_max_item then if v.order > coll_max_item then
coll_max_item = v.order coll_max_item = v.order
@ -36,17 +35,15 @@ function ReadCollection:prepareList(collection_name)
local data = self:read(collection_name) local data = self:read(collection_name)
local list = {} local list = {}
for _, v in pairs(data) do 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, { table.insert(list, {
order = v.order, order = v.order,
file = file_path,
text = v.file:gsub(".*/", ""), text = v.file:gsub(".*/", ""),
file = FFIUtil.realpath(v.file) or v.file, -- keep orig file path of deleted files dim = not file_exists,
dim = not file_exists, -- "dim", as expected by Menu mandatory = file_exists and util.getFriendlySize(lfs.attributes(file_path, "size") or 0),
mandatory = file_exists and util.getFriendlySize(lfs.attributes(v.file, "size") or 0), select_enabled = file_exists,
callback = function()
local ReaderUI = require("apps/reader/readerui")
ReaderUI:showReader(v.file)
end
}) })
end end
table.sort(list, function(v1,v2) table.sort(list, function(v1,v2)
@ -62,7 +59,7 @@ function ReadCollection:removeItemByPath(path, is_dir)
path = path .. "/" path = path .. "/"
end end
local coll = self:readAllCollection() local coll = self:readAllCollection()
for i, _ in pairs(coll) do for i in pairs(coll) do
local single_collection = coll[i] local single_collection = coll[i]
for item = #single_collection, 1, -1 do for item = #single_collection, 1, -1 do
if not is_dir and single_collection[item].file == path then if not is_dir and single_collection[item].file == path then
@ -126,19 +123,16 @@ function ReadCollection:removeItem(item, collection_name)
end end
function ReadCollection:writeCollection(coll_items, collection_name) function ReadCollection:writeCollection(coll_items, collection_name)
if not collection_name then collection_name = DEFAULT_COLLECTION_NAME end
local collection = LuaSettings:open(collection_file) local collection = LuaSettings:open(collection_file)
collection:saveSetting(collection_name, coll_items) collection:saveSetting(collection_name or DEFAULT_COLLECTION_NAME, coll_items)
collection:flush() collection:flush()
end end
function ReadCollection:addItem(file, collection_name) function ReadCollection:addItem(file, collection_name)
local coll, coll_max_item = self:read(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, file = file,
order = coll_max_item order = coll_max_item + 1,
} }
table.insert(coll, collection_item) table.insert(coll, collection_item)
self:writeCollection(coll, collection_name) self:writeCollection(coll, collection_name)
@ -151,8 +145,6 @@ function ReadCollection:checkItemExist(item, collection_name)
return true return true
end end
end end
return false
end end
return ReadCollection return ReadCollection

@ -89,6 +89,7 @@ function ButtonTable:init()
padding = Size.padding.buttontable, -- a bit taller than standalone buttons, for easier tap 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, padding_h = btn_entry.align == "left" and Size.padding.large or 0,
-- allow text to take more of the horizontal space if centered -- 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_face = btn_entry.font_face,
text_font_size = btn_entry.font_size, text_font_size = btn_entry.font_size,
text_font_bold = btn_entry.font_bold, text_font_bold = btn_entry.font_bold,

Loading…
Cancel
Save