mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
5e47a83e6a
Navigating the TOC, viewing a full screen image, browsing reading stats... would call paintTo() on ReaderUI (so, asking the engine to render the page) or FileManager (so, rendering cover images) even though their content is hidden. Widgets registering to UIManager have to explicitely states they cover the full screen (UIManager can't know, parts of their dimen may be transparent, e.g. if it is a CenterContainer).
802 lines
29 KiB
Lua
802 lines
29 KiB
Lua
local Blitbuffer = require("ffi/blitbuffer")
|
|
local Button = require("ui/widget/button")
|
|
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
|
local CenterContainer = require("ui/widget/container/centercontainer")
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
local Device = require("device")
|
|
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 FileManagerConverter = require("apps/filemanager/filemanagerconverter")
|
|
local FileManagerHistory = require("apps/filemanager/filemanagerhistory")
|
|
local FileManagerMenu = require("apps/filemanager/filemanagermenu")
|
|
local Font = require("ui/font")
|
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
|
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
|
local IconButton = require("ui/widget/iconbutton")
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local InputDialog = require("ui/widget/inputdialog")
|
|
local PluginLoader = require("pluginloader")
|
|
local ReaderDictionary = require("apps/reader/modules/readerdictionary")
|
|
local ReaderUI = require("apps/reader/readerui")
|
|
local ReaderWikipedia = require("apps/reader/modules/readerwikipedia")
|
|
local RenderText = require("ui/rendertext")
|
|
local Screenshoter = require("ui/widget/screenshoter")
|
|
local Size = require("ui/size")
|
|
local TextWidget = require("ui/widget/textwidget")
|
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
|
local VerticalSpan = require("ui/widget/verticalspan")
|
|
local UIManager = require("ui/uimanager")
|
|
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
|
local lfs = require("libs/libkoreader-lfs")
|
|
local logger = require("logger")
|
|
local util = require("ffi/util")
|
|
local _ = require("gettext")
|
|
local Screen = Device.screen
|
|
local T = require("ffi/util").template
|
|
|
|
local function restoreScreenMode()
|
|
local screen_mode = G_reader_settings:readSetting("fm_screen_mode")
|
|
if Screen:getScreenMode() ~= screen_mode then
|
|
Screen:setScreenMode(screen_mode or "portrait")
|
|
end
|
|
end
|
|
|
|
local function truncatePath(text)
|
|
local screen_width = Screen:getWidth()
|
|
local face = Font:getFace("xx_smallinfofont")
|
|
-- we want to truncate text on the left, so work with the reverse of text (which is fine as we don't use kerning)
|
|
local reversed_text = require("util").utf8Reverse(text)
|
|
local txt_width = RenderText:sizeUtf8Text(0, screen_width, face, reversed_text, false, false).x
|
|
if screen_width - 2 * Size.padding.small < txt_width then
|
|
reversed_text = RenderText:truncateTextByWidth(reversed_text, face, screen_width - 2 * Size.padding.small, false, false)
|
|
text = require("util").utf8Reverse(reversed_text)
|
|
end
|
|
return text
|
|
end
|
|
|
|
local FileManager = InputContainer:extend{
|
|
title = _("KOReader File Browser"),
|
|
root_path = lfs.currentdir(),
|
|
onExit = function() end,
|
|
|
|
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:init()
|
|
self.show_parent = self.show_parent or self
|
|
local icon_size = Screen:scaleBySize(35)
|
|
local home_button = IconButton:new{
|
|
icon_file = "resources/icons/appbar.home.png",
|
|
scale_for_dpi = false,
|
|
width = icon_size,
|
|
height = icon_size,
|
|
padding = Size.padding.default,
|
|
padding_left = Size.padding.large,
|
|
padding_right = Size.padding.large,
|
|
padding_bottom = 0,
|
|
callback = function() self:goHome() end,
|
|
hold_callback = function() self:setHome() end,
|
|
}
|
|
|
|
local plus_button = IconButton:new{
|
|
icon_file = "resources/icons/appbar.plus.png",
|
|
scale_for_dpi = false,
|
|
width = icon_size,
|
|
height = icon_size,
|
|
padding = Size.padding.default,
|
|
padding_left = Size.padding.large,
|
|
padding_right = Size.padding.large,
|
|
padding_bottom = 0,
|
|
callback = function() self:tapPlus() end,
|
|
}
|
|
|
|
self.path_text = TextWidget:new{
|
|
face = Font:getFace("xx_smallinfofont"),
|
|
text = truncatePath(filemanagerutil.abbreviate(self.root_path)),
|
|
}
|
|
|
|
self.banner = FrameContainer:new{
|
|
padding = 0,
|
|
bordersize = 0,
|
|
VerticalGroup:new {
|
|
CenterContainer:new {
|
|
dimen = { w = Screen:getWidth(), h = nil },
|
|
HorizontalGroup:new {
|
|
home_button,
|
|
VerticalGroup:new {
|
|
Button:new {
|
|
readonly = true,
|
|
bordersize = 0,
|
|
padding = 0,
|
|
text_font_bold = false,
|
|
text_font_face = "smalltfont",
|
|
text_font_size = 24,
|
|
text = self.title,
|
|
width = Screen:getWidth() - 2 * icon_size - 4 * Size.padding.large,
|
|
},
|
|
},
|
|
plus_button,
|
|
}
|
|
},
|
|
CenterContainer:new{
|
|
dimen = { w = Screen:getWidth(), h = nil },
|
|
self.path_text,
|
|
},
|
|
VerticalSpan:new{ width = Screen:scaleBySize(5) },
|
|
}
|
|
}
|
|
|
|
local g_show_hidden = G_reader_settings:readSetting("show_hidden")
|
|
local show_hidden = g_show_hidden == nil and DSHOWHIDDENFILES or g_show_hidden
|
|
local file_chooser = FileChooser:new{
|
|
-- remeber to adjust the height when new item is added to the group
|
|
path = self.root_path,
|
|
focused_path = self.focused_file,
|
|
collate = G_reader_settings:readSetting("collate") or "strcoll",
|
|
reverse_collate = G_reader_settings:isTrue("reverse_collate"),
|
|
show_parent = self.show_parent,
|
|
show_hidden = show_hidden,
|
|
width = Screen:getWidth(),
|
|
height = Screen:getHeight() - self.banner:getSize().h,
|
|
is_popout = false,
|
|
is_borderless = true,
|
|
has_close_button = true,
|
|
perpage = G_reader_settings:readSetting("items_per_page"),
|
|
file_filter = function(filename)
|
|
if DocumentRegistry:hasProvider(filename) then
|
|
return true
|
|
end
|
|
end,
|
|
close_callback = function() return self:onClose() end,
|
|
}
|
|
self.file_chooser = file_chooser
|
|
self.focused_file = nil -- use it only once
|
|
|
|
function file_chooser:onPathChanged(path) -- luacheck: ignore
|
|
FileManager.instance.path_text:setText(truncatePath(filemanagerutil.abbreviate(path)))
|
|
UIManager:setDirty(FileManager.instance, function()
|
|
return "ui", FileManager.instance.path_text.dimen
|
|
end)
|
|
return true
|
|
end
|
|
|
|
function file_chooser:onFileSelect(file) -- luacheck: ignore
|
|
FileManager.instance:onClose()
|
|
ReaderUI:showReader(file)
|
|
return true
|
|
end
|
|
|
|
local copyFile = function(file) self:copyFile(file) end
|
|
local pasteHere = function(file) self:pasteHere(file) end
|
|
local cutFile = function(file) self:cutFile(file) end
|
|
local deleteFile = function(file) self:deleteFile(file) end
|
|
local renameFile = function(file) self:renameFile(file) end
|
|
local setHome = function(path) self:setHome(path) end
|
|
local fileManager = self
|
|
|
|
function file_chooser:onFileHold(file) -- luacheck: ignore
|
|
local buttons = {
|
|
{
|
|
{
|
|
text = _("Copy"),
|
|
callback = function()
|
|
copyFile(file)
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Paste"),
|
|
enabled = fileManager.clipboard and true or false,
|
|
callback = function()
|
|
pasteHere(file)
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Purge .sdr"),
|
|
enabled = DocSettings:hasSidecarFile(util.realpath(file)),
|
|
callback = function()
|
|
UIManager:show(ConfirmBox:new{
|
|
text = util.template(_("Purge .sdr to reset settings for this document?\n\n%1"), self.file_dialog.title),
|
|
ok_text = _("Purge"),
|
|
ok_callback = function()
|
|
filemanagerutil.purgeSettings(file)
|
|
filemanagerutil.removeFileFromHistoryIfWanted(file)
|
|
self:refreshPath()
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
})
|
|
end,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
text = _("Cut"),
|
|
callback = function()
|
|
cutFile(file)
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Delete"),
|
|
callback = function()
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Are you sure that you want to delete this file?\n") .. file .. ("\n") .. _("If you delete a file, it is permanently lost."),
|
|
ok_text = _("Delete"),
|
|
ok_callback = function()
|
|
deleteFile(file)
|
|
filemanagerutil.removeFileFromHistoryIfWanted(file)
|
|
self:refreshPath()
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
})
|
|
end,
|
|
},
|
|
{
|
|
text = _("Rename"),
|
|
callback = function()
|
|
UIManager:close(self.file_dialog)
|
|
fileManager.rename_dialog = InputDialog:new{
|
|
title = _("Rename file"),
|
|
input = util.basename(file),
|
|
buttons = {{
|
|
{
|
|
text = _("Cancel"),
|
|
enabled = true,
|
|
callback = function()
|
|
UIManager:close(fileManager.rename_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Rename"),
|
|
enabled = true,
|
|
callback = function()
|
|
renameFile(file)
|
|
self:refreshPath()
|
|
UIManager:close(fileManager.rename_dialog)
|
|
end,
|
|
},
|
|
}},
|
|
}
|
|
fileManager.rename_dialog:onShowKeyboard()
|
|
UIManager:show(fileManager.rename_dialog)
|
|
end,
|
|
}
|
|
},
|
|
-- a little hack to get visual functionality grouping
|
|
{},
|
|
{
|
|
{
|
|
text = _("Open with…"),
|
|
enabled = lfs.attributes(file, "mode") == "file"
|
|
and #(DocumentRegistry:getProviders(file)) > 1,
|
|
callback = function()
|
|
UIManager:close(self.file_dialog)
|
|
DocumentRegistry:showSetProviderButtons(file, FileManager.instance, self, ReaderUI)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Convert"),
|
|
enabled = lfs.attributes(file, "mode") == "file"
|
|
and FileManagerConverter:isSupported(file),
|
|
callback = function()
|
|
UIManager:close(self.file_dialog)
|
|
FileManagerConverter:showConvertButtons(file, self)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Book information"),
|
|
enabled = FileManagerBookInfo:isSupported(file),
|
|
callback = function()
|
|
FileManagerBookInfo:show(file)
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
},
|
|
},
|
|
}
|
|
if lfs.attributes(file, "mode") == "directory" then
|
|
local realpath = util.realpath(file)
|
|
table.insert(buttons, {
|
|
{
|
|
text = _("Set as HOME directory"),
|
|
callback = function()
|
|
setHome(realpath)
|
|
UIManager:close(self.file_dialog)
|
|
end
|
|
}
|
|
})
|
|
end
|
|
|
|
self.file_dialog = ButtonDialogTitle:new{
|
|
title = file:match("([^/]+)$"),
|
|
title_align = "center",
|
|
buttons = buttons,
|
|
}
|
|
UIManager:show(self.file_dialog)
|
|
return true
|
|
end
|
|
|
|
self.layout = VerticalGroup:new{
|
|
self.banner,
|
|
file_chooser,
|
|
}
|
|
|
|
local fm_ui = FrameContainer:new{
|
|
padding = 0,
|
|
bordersize = 0,
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
self.layout,
|
|
}
|
|
|
|
self[1] = fm_ui
|
|
|
|
self.menu = FileManagerMenu:new{
|
|
ui = self
|
|
}
|
|
self.active_widgets = { Screenshoter:new{ prefix = 'FileManager' } }
|
|
table.insert(self, self.menu)
|
|
table.insert(self, FileManagerHistory:new{
|
|
ui = self,
|
|
})
|
|
table.insert(self, ReaderDictionary:new{ ui = self })
|
|
table.insert(self, ReaderWikipedia:new{ ui = self })
|
|
|
|
-- koreader plugins
|
|
for _,plugin_module in ipairs(PluginLoader:loadPlugins()) do
|
|
if not plugin_module.is_doc_only then
|
|
local ok, plugin_or_err = PluginLoader:createPluginInstance(
|
|
plugin_module, { ui = self, })
|
|
-- Keep references to the modules which do not register into menu.
|
|
if ok then
|
|
table.insert(self, plugin_or_err)
|
|
logger.info("FM loaded plugin", plugin_module.name,
|
|
"at", plugin_module.path)
|
|
end
|
|
end
|
|
end
|
|
|
|
if Device:hasKeys() then
|
|
self.key_events.Home = { {"Home"}, doc = "go home" }
|
|
if not Device:isSDL() then
|
|
--if not in the desktop emulator
|
|
--remove the old Back key to exit koreader
|
|
self.file_chooser.key_events.Close = nil
|
|
end
|
|
end
|
|
|
|
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
|
end
|
|
|
|
function FileManager:tapPlus()
|
|
local buttons = {
|
|
{
|
|
{
|
|
text = _("New folder"),
|
|
callback = function()
|
|
UIManager:close(self.file_dialog)
|
|
self.input_dialog = InputDialog:new{
|
|
title = _("Create new folder"),
|
|
input_type = "text",
|
|
buttons = {
|
|
{
|
|
{
|
|
text = _("Cancel"),
|
|
callback = function()
|
|
self:closeInputDialog()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Create"),
|
|
callback = function()
|
|
self:closeInputDialog()
|
|
local new_folder = self.input_dialog:getInputText()
|
|
if new_folder and new_folder ~= "" then
|
|
self:createFolder(self.file_chooser.path, new_folder)
|
|
end
|
|
end,
|
|
},
|
|
}
|
|
},
|
|
}
|
|
self.input_dialog:onShowKeyboard()
|
|
UIManager:show(self.input_dialog)
|
|
end,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
text = _("Paste"),
|
|
enabled = self.clipboard and true or false,
|
|
callback = function()
|
|
self:pasteHere(self.file_chooser.path)
|
|
self:onRefresh()
|
|
UIManager:close(self.file_dialog)
|
|
end,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
text = _("Set as HOME directory"),
|
|
callback = function()
|
|
self:setHome(self.file_chooser.path)
|
|
UIManager:close(self.file_dialog)
|
|
end
|
|
}
|
|
},
|
|
{
|
|
{
|
|
text = _("Go to HOME directory"),
|
|
callback = function()
|
|
self:goHome()
|
|
UIManager:close(self.file_dialog)
|
|
end
|
|
}
|
|
}
|
|
}
|
|
|
|
self.file_dialog = ButtonDialogTitle:new{
|
|
title = filemanagerutil.abbreviate(self.file_chooser.path),
|
|
title_align = "center",
|
|
buttons = buttons,
|
|
}
|
|
UIManager:show(self.file_dialog)
|
|
end
|
|
|
|
function FileManager:reinit(path, focused_file)
|
|
self.dimen = Screen:getSize()
|
|
-- backup the root path and path items
|
|
self.root_path = path or self.file_chooser.path
|
|
local path_items_backup = {}
|
|
for k, v in pairs(self.file_chooser.path_items) do
|
|
path_items_backup[k] = v
|
|
end
|
|
-- reinit filemanager
|
|
self.focused_file = focused_file
|
|
self:init()
|
|
self.file_chooser.path_items = path_items_backup
|
|
-- self:init() has already done file_chooser:refreshPath(), so this one
|
|
-- looks like not necessary (cheap with classic mode, less cheap with
|
|
-- CoverBrowser plugin's cover image renderings)
|
|
-- self:onRefresh()
|
|
end
|
|
|
|
function FileManager:toggleHiddenFiles()
|
|
self.file_chooser:toggleHiddenFiles()
|
|
G_reader_settings:saveSetting("show_hidden", self.file_chooser.show_hidden)
|
|
end
|
|
|
|
function FileManager:setCollate(collate)
|
|
self.file_chooser:setCollate(collate)
|
|
G_reader_settings:saveSetting("collate", self.file_chooser.collate)
|
|
end
|
|
|
|
function FileManager:toggleReverseCollate()
|
|
self.file_chooser:toggleReverseCollate()
|
|
G_reader_settings:saveSetting("reverse_collate", self.file_chooser.reverse_collate)
|
|
end
|
|
|
|
function FileManager:onClose()
|
|
logger.dbg("close filemanager")
|
|
G_reader_settings:flush()
|
|
UIManager:close(self)
|
|
if self.onExit then
|
|
self:onExit()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function FileManager:onRefresh()
|
|
self.file_chooser:refreshPath()
|
|
return true
|
|
end
|
|
|
|
function FileManager:goHome()
|
|
local home_dir = G_reader_settings:readSetting("home_dir")
|
|
if home_dir then
|
|
self.file_chooser:changeToPath(home_dir)
|
|
else
|
|
self:setHome()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function FileManager:setHome(path)
|
|
path = path or self.file_chooser.path
|
|
UIManager:show(ConfirmBox:new{
|
|
text = util.template(_("Set '%1' as HOME directory?"), path),
|
|
ok_text = _("Set as HOME"),
|
|
ok_callback = function()
|
|
G_reader_settings:saveSetting("home_dir", path)
|
|
end,
|
|
})
|
|
return true
|
|
end
|
|
|
|
function FileManager:copyFile(file)
|
|
self.cutfile = false
|
|
self.clipboard = file
|
|
end
|
|
|
|
function FileManager:cutFile(file)
|
|
self.cutfile = true
|
|
self.clipboard = file
|
|
end
|
|
|
|
function FileManager:pasteHere(file)
|
|
if self.clipboard then
|
|
file = util.realpath(file)
|
|
local orig = util.realpath(self.clipboard)
|
|
local dest = lfs.attributes(file, "mode") == "directory" and
|
|
file or file:match("(.*/)")
|
|
|
|
local function infoCopyFile()
|
|
-- if we copy a file, also copy its sidecar directory
|
|
if DocSettings:hasSidecarFile(orig) then
|
|
util.execute(self.cp_bin, "-r", DocSettings:getSidecarDir(orig), dest)
|
|
end
|
|
if util.execute(self.cp_bin, "-r", orig, dest) == 0 then
|
|
UIManager:show(InfoMessage:new {
|
|
text = T(_("Copied to: %1"), dest),
|
|
timeout = 2,
|
|
})
|
|
else
|
|
UIManager:show(InfoMessage:new {
|
|
text = T(_("An error occurred while trying to copy %1"), orig),
|
|
timeout = 2,
|
|
})
|
|
end
|
|
end
|
|
|
|
local function infoMoveFile()
|
|
-- if we move a file, also move its sidecar directory
|
|
if DocSettings:hasSidecarFile(orig) then
|
|
self:moveFile(DocSettings:getSidecarDir(orig), dest) -- dest is always a directory
|
|
end
|
|
if self:moveFile(orig, dest) then
|
|
--update history
|
|
local dest_file = string.format("%s/%s", dest, util.basename(orig))
|
|
require("readhistory"):updateItemByPath(orig, dest_file)
|
|
--update last open file
|
|
if G_reader_settings:readSetting("lastfile") == orig then
|
|
G_reader_settings:saveSetting("lastfile", dest_file)
|
|
end
|
|
UIManager:show(InfoMessage:new {
|
|
text = T(_("Moved to: %1"), dest),
|
|
timeout = 2,
|
|
})
|
|
else
|
|
UIManager:show(InfoMessage:new {
|
|
text = T(_("An error occurred while trying to move %1"), orig),
|
|
timeout = 2,
|
|
})
|
|
end
|
|
util.execute(self.cp_bin, "-r", orig, dest)
|
|
end
|
|
|
|
local info_file
|
|
if self.cutfile then
|
|
info_file = infoMoveFile
|
|
else
|
|
info_file = infoCopyFile
|
|
end
|
|
local basename = util.basename(self.clipboard)
|
|
local mode = lfs.attributes(string.format("%s/%s", dest, basename), "mode")
|
|
if mode == "file" or mode == "directory" then
|
|
local text
|
|
if mode == "file" then
|
|
text = T(_("The file %1 already exists. Do you want to overwrite it?"), basename)
|
|
else
|
|
text = T(_("The directory %1 already exists. Do you want to overwrite it?"), basename)
|
|
end
|
|
|
|
UIManager:show(ConfirmBox:new {
|
|
text = text,
|
|
ok_text = _("Overwrite"),
|
|
ok_callback = function()
|
|
info_file()
|
|
self:onRefresh()
|
|
end,
|
|
})
|
|
else
|
|
info_file()
|
|
self:onRefresh()
|
|
end
|
|
end
|
|
end
|
|
|
|
function FileManager:createFolder(curr_folder, new_folder)
|
|
local folder = string.format("%s/%s", curr_folder, new_folder)
|
|
local code = util.execute(self.mkdir_bin, folder)
|
|
local text
|
|
if code == 0 then
|
|
self:onRefresh()
|
|
text = T(_("Folder created:\n%1"), new_folder)
|
|
else
|
|
text = _("The folder has not been created.")
|
|
end
|
|
UIManager:show(InfoMessage:new{
|
|
text = text,
|
|
timeout = 2,
|
|
})
|
|
end
|
|
|
|
function FileManager:deleteFile(file)
|
|
local ok, err
|
|
local file_abs_path = util.realpath(file)
|
|
if file_abs_path == nil then
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(_("File %1 not found"), file),
|
|
})
|
|
return
|
|
end
|
|
|
|
local is_doc = DocumentRegistry:hasProvider(file_abs_path)
|
|
if lfs.attributes(file_abs_path, "mode") == "file" then
|
|
ok, err = os.remove(file_abs_path)
|
|
else
|
|
ok, err = util.purgeDir(file_abs_path)
|
|
end
|
|
if ok and not err then
|
|
if is_doc then
|
|
DocSettings:open(file):purge()
|
|
end
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(_("Deleted %1"), file),
|
|
timeout = 2,
|
|
})
|
|
else
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(_("An error occurred while trying to delete %1"), file),
|
|
})
|
|
end
|
|
end
|
|
|
|
function FileManager:renameFile(file)
|
|
if util.basename(file) ~= self.rename_dialog:getInputText() then
|
|
local dest = util.joinPath(util.dirname(file), self.rename_dialog:getInputText())
|
|
if self:moveFile(file, dest) then
|
|
if lfs.attributes(dest, "mode") == "file" then
|
|
local doc = require("docsettings")
|
|
local move_history = true;
|
|
if lfs.attributes(doc:getHistoryPath(file), "mode") == "file" and
|
|
not self:moveFile(doc:getHistoryPath(file), doc:getHistoryPath(dest)) then
|
|
move_history = false
|
|
end
|
|
if lfs.attributes(doc:getSidecarDir(file), "mode") == "directory" and
|
|
not self:moveFile(doc:getSidecarDir(file), doc:getSidecarDir(dest)) then
|
|
move_history = false
|
|
end
|
|
if move_history then
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(_("Renamed from %1 to %2"), file, dest),
|
|
timeout = 2,
|
|
})
|
|
else
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(
|
|
_("Failed to move history data of %1 to %2.\nThe reading history may be lost."),
|
|
file, dest),
|
|
})
|
|
end
|
|
end
|
|
else
|
|
UIManager:show(InfoMessage:new{
|
|
text = util.template(
|
|
_("Failed to rename from %1 to %2"), file, dest),
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
function FileManager:getSortingMenuTable()
|
|
local fm = self
|
|
local collates = {
|
|
strcoll = {_("title"), _("Sort by title")},
|
|
access = {_("date read"), _("Sort by last read date")},
|
|
change = {_("date added"), _("Sort by date added")},
|
|
modification = {_("date modified"), _("Sort by date modified")},
|
|
size = {_("size"), _("Sort by size")},
|
|
type = {_("type"), _("Sort by type")},
|
|
percent_unopened_first = {_("percent - unopened first"), _("Sort by percent - unopened first")},
|
|
percent_unopened_last = {_("percent - unopened last"), _("Sort by percent - unopened last")},
|
|
}
|
|
local set_collate_table = function(collate)
|
|
return {
|
|
text = collates[collate][2],
|
|
checked_func = function()
|
|
return fm.file_chooser.collate == collate
|
|
end,
|
|
callback = function() fm:setCollate(collate) end,
|
|
}
|
|
end
|
|
return {
|
|
text_func = function()
|
|
return util.template(
|
|
_("Sort by: %1"),
|
|
collates[fm.file_chooser.collate][1]
|
|
)
|
|
end,
|
|
sub_item_table = {
|
|
set_collate_table("strcoll"),
|
|
set_collate_table("access"),
|
|
set_collate_table("change"),
|
|
set_collate_table("modification"),
|
|
set_collate_table("size"),
|
|
set_collate_table("type"),
|
|
set_collate_table("percent_unopened_first"),
|
|
set_collate_table("percent_unopened_last"),
|
|
}
|
|
}
|
|
end
|
|
|
|
function FileManager:getStartWithMenuTable()
|
|
local start_with_setting = G_reader_settings:readSetting("start_with") or "filemanager"
|
|
local start_withs = {
|
|
filemanager = {_("file browser"), _("Start with file browser")},
|
|
history = {_("history"), _("Start with history")},
|
|
last = {_("last file"), _("Start with last file")},
|
|
}
|
|
local set_sw_table = function(start_with)
|
|
return {
|
|
text = start_withs[start_with][2],
|
|
checked_func = function()
|
|
return start_with_setting == start_with
|
|
end,
|
|
callback = function()
|
|
start_with_setting = start_with
|
|
G_reader_settings:saveSetting("start_with", start_with)
|
|
end,
|
|
}
|
|
end
|
|
return {
|
|
text_func = function()
|
|
return util.template(
|
|
_("Start with: %1"),
|
|
start_withs[start_with_setting][1]
|
|
)
|
|
end,
|
|
sub_item_table = {
|
|
set_sw_table("filemanager"),
|
|
set_sw_table("history"),
|
|
set_sw_table("last"),
|
|
}
|
|
}
|
|
end
|
|
|
|
function FileManager:showFiles(path, focused_file)
|
|
path = path or G_reader_settings:readSetting("lastdir") or filemanagerutil.getDefaultDir()
|
|
G_reader_settings:saveSetting("lastdir", path)
|
|
restoreScreenMode()
|
|
local file_manager = FileManager:new{
|
|
dimen = Screen:getSize(),
|
|
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
|
root_path = path,
|
|
focused_file = focused_file,
|
|
onExit = function()
|
|
self.instance = nil
|
|
end
|
|
}
|
|
UIManager:show(file_manager)
|
|
self.instance = file_manager
|
|
end
|
|
|
|
--[[
|
|
A shortcut to execute mv command (self.mv_bin) with from and to as parameters.
|
|
Returns a boolean value to indicate the result of mv command.
|
|
--]]
|
|
function FileManager:moveFile(from, to)
|
|
return util.execute(self.mv_bin, from, to) == 0
|
|
end
|
|
|
|
function FileManager:onHome()
|
|
return self:goHome()
|
|
end
|
|
|
|
return FileManager
|