mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Profiles: more auto-exec triggers 2 (#12691)
This commit is contained in:
@@ -33,16 +33,16 @@ local ReadHistory = require("readhistory")
|
||||
local Screenshoter = require("ui/widget/screenshoter")
|
||||
local TitleBar = require("ui/widget/titlebar")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local BaseUtil = require("ffi/util")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local C_ = _.pgettext
|
||||
local N_ = _.ngettext
|
||||
local Screen = Device.screen
|
||||
local T = BaseUtil.template
|
||||
local T = ffiUtil.template
|
||||
|
||||
local FileManager = InputContainer:extend{
|
||||
title = _("KOReader"),
|
||||
@@ -106,14 +106,15 @@ function FileManager:onSetDimensions(dimen)
|
||||
end
|
||||
|
||||
function FileManager:updateTitleBarPath(path)
|
||||
path = path or self.file_chooser.path
|
||||
local text = BD.directory(filemanagerutil.abbreviate(path))
|
||||
if FileManagerShortcuts:hasFolderShortcut(path) then
|
||||
if self.folder_shortcuts:hasFolderShortcut(path) then
|
||||
text = "☆ " .. text
|
||||
end
|
||||
self.title_bar:setSubTitle(text)
|
||||
end
|
||||
|
||||
FileManager.onPathChanged = FileManager.updateTitleBarPath
|
||||
|
||||
function FileManager:setupLayout()
|
||||
self.show_parent = self.show_parent or self
|
||||
self.title_bar = TitleBar:new{
|
||||
@@ -135,7 +136,6 @@ function FileManager:setupLayout()
|
||||
right_icon_tap_callback = function() self:onShowPlusMenu() end,
|
||||
right_icon_hold_callback = false, -- propagate long-press to dispatcher
|
||||
}
|
||||
self:updateTitleBarPath(self.root_path)
|
||||
|
||||
local file_chooser = FileChooser:new{
|
||||
path = self.root_path,
|
||||
@@ -158,11 +158,6 @@ function FileManager:setupLayout()
|
||||
|
||||
local file_manager = self
|
||||
|
||||
function file_chooser:onPathChanged(path)
|
||||
file_manager:updateTitleBarPath(path)
|
||||
return true
|
||||
end
|
||||
|
||||
function file_chooser:onFileSelect(item)
|
||||
if file_manager.selected_files then -- toggle selection
|
||||
item.dim = not item.dim and true or nil
|
||||
@@ -262,7 +257,7 @@ function FileManager:setupLayout()
|
||||
self.book_props = nil -- in 'self' to provide access to it in CoverBrowser
|
||||
local has_provider = DocumentRegistry:hasProvider(file)
|
||||
local has_sidecar = DocSettings:hasSidecarFile(file)
|
||||
local doc_settings_or_file
|
||||
local doc_settings_or_file = file
|
||||
if has_provider or has_sidecar then
|
||||
self.book_props = file_manager.coverbrowser and file_manager.coverbrowser:getBookInfo(file)
|
||||
if has_sidecar then
|
||||
@@ -272,8 +267,6 @@ function FileManager:setupLayout()
|
||||
self.book_props = FileManagerBookInfo.extendProps(props, file)
|
||||
self.book_props.has_cover = true -- to enable "Book cover" button, we do not know if cover exists
|
||||
end
|
||||
else
|
||||
doc_settings_or_file = file
|
||||
end
|
||||
table.insert(buttons, filemanagerutil.genStatusButtonsRow(doc_settings_or_file, close_dialog_refresh_callback))
|
||||
table.insert(buttons, {}) -- separator
|
||||
@@ -315,7 +308,7 @@ function FileManager:setupLayout()
|
||||
})
|
||||
end
|
||||
else -- folder
|
||||
local folder = BaseUtil.realpath(file)
|
||||
local folder = ffiUtil.realpath(file)
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = _("Set as HOME folder"),
|
||||
@@ -431,6 +424,7 @@ function FileManager:init()
|
||||
|
||||
self:initGesListener()
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
self:handleEvent(Event:new("PathChanged", self.file_chooser.path))
|
||||
|
||||
if FileManager.instance == nil then
|
||||
logger.dbg("Spinning up new FileManager instance", tostring(self))
|
||||
@@ -726,7 +720,7 @@ function FileManager:reinit(path, focused_file)
|
||||
UIManager:flushSettings()
|
||||
self.dimen = Screen:getSize()
|
||||
-- backup the root path and path items
|
||||
self.root_path = BaseUtil.realpath(path or self.file_chooser.path)
|
||||
self.root_path = ffiUtil.realpath(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
|
||||
@@ -826,7 +820,7 @@ function FileManager:openRandomFile(dir)
|
||||
local random_file = filemanagerutil.getRandomFile(dir, match_func)
|
||||
if random_file then
|
||||
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(ffiUtil.basename(random_file))),
|
||||
choice1_text = _("Open"),
|
||||
choice1_callback = function()
|
||||
local ReaderUI = require("apps/reader/readerui")
|
||||
@@ -856,11 +850,11 @@ function FileManager:cutFile(file)
|
||||
end
|
||||
|
||||
function FileManager:pasteFileFromClipboard(file)
|
||||
local orig_file = BaseUtil.realpath(self.clipboard)
|
||||
local orig_name = BaseUtil.basename(orig_file)
|
||||
local dest_path = BaseUtil.realpath(file or self.file_chooser.path)
|
||||
local orig_file = ffiUtil.realpath(self.clipboard)
|
||||
local orig_name = ffiUtil.basename(orig_file)
|
||||
local dest_path = ffiUtil.realpath(file or self.file_chooser.path)
|
||||
dest_path = isFile(dest_path) and dest_path:match("(.*/)") or dest_path
|
||||
local dest_file = BaseUtil.joinPath(dest_path, orig_name)
|
||||
local dest_file = ffiUtil.joinPath(dest_path, orig_name)
|
||||
if orig_file == dest_file or orig_file == dest_path then -- do not paste to itself
|
||||
self.clipboard = nil
|
||||
return
|
||||
@@ -951,12 +945,12 @@ function FileManager:showCopyMoveSelectedFilesDialog(close_callback)
|
||||
end
|
||||
|
||||
function FileManager:pasteSelectedFiles(overwrite)
|
||||
local dest_path = BaseUtil.realpath(self.file_chooser.path)
|
||||
local dest_path = ffiUtil.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)
|
||||
if BaseUtil.realpath(orig_file) == dest_file then -- do not paste to itself
|
||||
local orig_name = ffiUtil.basename(orig_file)
|
||||
local dest_file = ffiUtil.joinPath(dest_path, orig_name)
|
||||
if ffiUtil.realpath(orig_file) == dest_file then -- do not paste to itself
|
||||
self.selected_files[orig_file] = nil
|
||||
else
|
||||
local ok
|
||||
@@ -1046,7 +1040,7 @@ function FileManager:createFolder()
|
||||
end
|
||||
|
||||
function FileManager:showDeleteFileDialog(filepath, post_delete_callback, pre_delete_callback)
|
||||
local file = BaseUtil.realpath(filepath)
|
||||
local file = ffiUtil.realpath(filepath)
|
||||
if file == nil then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("File not found:\n%1"), BD.filepath(filepath)),
|
||||
@@ -1083,7 +1077,7 @@ function FileManager:deleteFile(file, is_file)
|
||||
return true
|
||||
end
|
||||
else
|
||||
local ok = BaseUtil.purgeDir(file)
|
||||
local ok = ffiUtil.purgeDir(file)
|
||||
if ok then
|
||||
ReadHistory:folderDeleted(file) -- will delete sdr
|
||||
ReadCollection:removeItemsByPath(file)
|
||||
@@ -1099,7 +1093,7 @@ 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 file_abs_path = ffiUtil.realpath(orig_file)
|
||||
local ok = file_abs_path and os.remove(file_abs_path)
|
||||
if ok then
|
||||
DocSettings.updateLocation(file_abs_path) -- delete sdr
|
||||
@@ -1129,7 +1123,7 @@ function FileManager:showRenameFileDialog(file, is_file)
|
||||
local dialog
|
||||
dialog = InputDialog:new{
|
||||
title = is_file and _("Rename file") or _("Rename folder"),
|
||||
input = BaseUtil.basename(file),
|
||||
input = ffiUtil.basename(file),
|
||||
buttons = {{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
@@ -1155,8 +1149,8 @@ function FileManager:showRenameFileDialog(file, is_file)
|
||||
end
|
||||
|
||||
function FileManager:renameFile(file, basename, is_file)
|
||||
if BaseUtil.basename(file) == basename then return end
|
||||
local dest = BaseUtil.joinPath(BaseUtil.dirname(file), basename)
|
||||
if ffiUtil.basename(file) == basename then return end
|
||||
local dest = ffiUtil.joinPath(ffiUtil.dirname(file), basename)
|
||||
|
||||
local function doRenameFile()
|
||||
if self:moveFile(file, dest) then
|
||||
@@ -1220,7 +1214,7 @@ function FileManager:showFiles(path, focused_file, selected_files)
|
||||
FileManager.instance:onClose()
|
||||
end
|
||||
|
||||
path = BaseUtil.realpath(path or G_reader_settings:readSetting("lastdir") or filemanagerutil.getDefaultDir())
|
||||
path = ffiUtil.realpath(path or G_reader_settings:readSetting("lastdir") or filemanagerutil.getDefaultDir())
|
||||
G_reader_settings:saveSetting("lastdir", path)
|
||||
self:setRotationMode()
|
||||
local file_manager = FileManager:new{
|
||||
@@ -1236,19 +1230,19 @@ end
|
||||
--- A shortcut to execute mv.
|
||||
-- @treturn boolean result of mv command
|
||||
function FileManager:moveFile(from, to)
|
||||
return BaseUtil.execute(self.mv_bin, from, to) == 0
|
||||
return ffiUtil.execute(self.mv_bin, from, to) == 0
|
||||
end
|
||||
|
||||
--- A shortcut to execute cp.
|
||||
-- @treturn boolean result of cp command
|
||||
function FileManager:copyFileFromTo(from, to)
|
||||
return BaseUtil.execute(self.cp_bin, from, to) == 0
|
||||
return ffiUtil.execute(self.cp_bin, from, to) == 0
|
||||
end
|
||||
|
||||
--- A shortcut to execute cp recursively.
|
||||
-- @treturn boolean result of cp command
|
||||
function FileManager:copyRecursive(from, to)
|
||||
return BaseUtil.execute(self.cp_bin, "-r", from, to ) == 0
|
||||
return ffiUtil.execute(self.cp_bin, "-r", from, to ) == 0
|
||||
end
|
||||
|
||||
function FileManager:onHome()
|
||||
@@ -1341,9 +1335,9 @@ function FileManager:showSelectedFilesList()
|
||||
local a_path, a_name = util.splitFilePathName(a.text)
|
||||
local b_path, b_name = util.splitFilePathName(b.text)
|
||||
if a_path == b_path then
|
||||
return BaseUtil.strcoll(a_name, b_name)
|
||||
return ffiUtil.strcoll(a_name, b_name)
|
||||
end
|
||||
return BaseUtil.strcoll(a_path, b_path)
|
||||
return ffiUtil.strcoll(a_path, b_path)
|
||||
end
|
||||
table.sort(selected_files, sorting)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local Device = require("device")
|
||||
local DocSettings = require("docsettings")
|
||||
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local Menu = require("ui/widget/menu")
|
||||
@@ -70,12 +69,17 @@ function FileManagerCollection:onShowColl(collection_name)
|
||||
title_bar_fm_style = true,
|
||||
title_bar_left_icon = "appbar.menu",
|
||||
onLeftButtonTap = function() self:showCollDialog() end,
|
||||
onReturn = function()
|
||||
self.coll_menu.close_callback()
|
||||
self:onShowCollList()
|
||||
end,
|
||||
onMenuChoice = self.onMenuChoice,
|
||||
onMenuHold = self.onMenuHold,
|
||||
_manager = self,
|
||||
_recreate_func = function() self:onShowColl(collection_name) end,
|
||||
collection_name = collection_name,
|
||||
}
|
||||
table.insert(self.coll_menu.paths, true) -- enable onReturn button
|
||||
self.coll_menu.close_callback = function()
|
||||
self:refreshFileManager()
|
||||
UIManager:close(self.coll_menu)
|
||||
@@ -146,7 +150,7 @@ function FileManagerCollection:onMenuHold(item)
|
||||
doc_settings_or_file = DocSettings:open(file)
|
||||
if not self.book_props then
|
||||
local props = doc_settings_or_file:readSetting("doc_props")
|
||||
self.book_props = FileManagerBookInfo.extendProps(props, file)
|
||||
self.book_props = self.ui.bookinfo.extendProps(props, file)
|
||||
self.book_props.has_cover = true
|
||||
end
|
||||
else
|
||||
@@ -285,14 +289,18 @@ end
|
||||
|
||||
-- collection list
|
||||
|
||||
function FileManagerCollection:onShowCollList(file_or_files, caller_callback, no_dialog)
|
||||
self.selected_colections = nil
|
||||
if file_or_files then -- select mode
|
||||
if type(file_or_files) == "string" then -- checkmark collections containing the file
|
||||
self.selected_colections = ReadCollection:getCollectionsWithFile(file_or_files)
|
||||
else -- do not checkmark any
|
||||
self.selected_colections = {}
|
||||
function FileManagerCollection:onShowCollList(file_or_selected_collections, caller_callback, no_dialog)
|
||||
local title_bar_left_icon
|
||||
if file_or_selected_collections ~= nil then -- select mode
|
||||
title_bar_left_icon = "check"
|
||||
if type(file_or_selected_collections) == "string" then -- checkmark collections containing the file
|
||||
self.selected_collections = ReadCollection:getCollectionsWithFile(file_or_selected_collections)
|
||||
else
|
||||
self.selected_collections = util.tableDeepCopy(file_or_selected_collections)
|
||||
end
|
||||
else
|
||||
title_bar_left_icon = "appbar.menu"
|
||||
self.selected_collections = nil
|
||||
end
|
||||
self.coll_list = Menu:new{
|
||||
subtitle = "",
|
||||
@@ -300,15 +308,15 @@ function FileManagerCollection:onShowCollList(file_or_files, caller_callback, no
|
||||
is_borderless = true,
|
||||
is_popout = false,
|
||||
title_bar_fm_style = true,
|
||||
title_bar_left_icon = file_or_files and "check" or "appbar.menu",
|
||||
title_bar_left_icon = title_bar_left_icon,
|
||||
onLeftButtonTap = function() self:showCollListDialog(caller_callback, no_dialog) end,
|
||||
onMenuChoice = self.onCollListChoice,
|
||||
onMenuHold = self.onCollListHold,
|
||||
_manager = self,
|
||||
_recreate_func = function() self:onShowCollList(file_or_files, caller_callback, no_dialog) end,
|
||||
_recreate_func = function() self:onShowCollList(file_or_selected_collections, caller_callback, no_dialog) end,
|
||||
}
|
||||
self.coll_list.close_callback = function(force_close)
|
||||
if force_close or self.selected_colections == nil then
|
||||
if force_close or self.selected_collections == nil then
|
||||
self:refreshFileManager()
|
||||
UIManager:close(self.coll_list)
|
||||
self.coll_list = nil
|
||||
@@ -325,8 +333,8 @@ function FileManagerCollection:updateCollListItemTable(do_init, item_number)
|
||||
item_table = {}
|
||||
for name, coll in pairs(ReadCollection.coll) do
|
||||
local mandatory
|
||||
if self.selected_colections then
|
||||
mandatory = self.selected_colections[name] and self.checkmark or " "
|
||||
if self.selected_collections then
|
||||
mandatory = self.selected_collections[name] and self.checkmark or " "
|
||||
self.coll_list.items_mandatory_font_size = self.coll_list.font_size
|
||||
else
|
||||
mandatory = util.tableSize(coll)
|
||||
@@ -346,12 +354,12 @@ function FileManagerCollection:updateCollListItemTable(do_init, item_number)
|
||||
end
|
||||
local title = T(_("Collections (%1)"), #item_table)
|
||||
local subtitle
|
||||
if self.selected_colections then
|
||||
local selected_nb = util.tableSize(self.selected_colections)
|
||||
subtitle = self.selected_colections and T(_("Selected: %1"), selected_nb)
|
||||
if self.selected_collections then
|
||||
local selected_nb = util.tableSize(self.selected_collections)
|
||||
subtitle = self.selected_collections and T(_("Selected: %1"), selected_nb)
|
||||
if do_init and selected_nb > 0 then -- show first collection containing the long-pressed book
|
||||
for i, item in ipairs(item_table) do
|
||||
if self.selected_colections[item.name] then
|
||||
if self.selected_collections[item.name] then
|
||||
item_number = i
|
||||
break
|
||||
end
|
||||
@@ -362,13 +370,13 @@ function FileManagerCollection:updateCollListItemTable(do_init, item_number)
|
||||
end
|
||||
|
||||
function FileManagerCollection:onCollListChoice(item)
|
||||
if self._manager.selected_colections then
|
||||
if self._manager.selected_collections then
|
||||
if item.mandatory == self._manager.checkmark then
|
||||
self.item_table[item.idx].mandatory = " "
|
||||
self._manager.selected_colections[item.name] = nil
|
||||
self._manager.selected_collections[item.name] = nil
|
||||
else
|
||||
self.item_table[item.idx].mandatory = self._manager.checkmark
|
||||
self._manager.selected_colections[item.name] = true
|
||||
self._manager.selected_collections[item.name] = true
|
||||
end
|
||||
self._manager:updateCollListItemTable()
|
||||
else
|
||||
@@ -378,7 +386,7 @@ end
|
||||
|
||||
function FileManagerCollection:onCollListHold(item)
|
||||
if item.name == ReadCollection.default_collection_name -- Favorites non-editable
|
||||
or self._manager.selected_colections then -- select mode
|
||||
or self._manager.selected_collections then -- select mode
|
||||
return
|
||||
end
|
||||
|
||||
@@ -412,7 +420,7 @@ end
|
||||
|
||||
function FileManagerCollection:showCollListDialog(caller_callback, no_dialog)
|
||||
if no_dialog then
|
||||
caller_callback()
|
||||
caller_callback(self.selected_collections)
|
||||
self.coll_list.close_callback(true)
|
||||
return
|
||||
end
|
||||
@@ -427,7 +435,7 @@ function FileManagerCollection:showCollListDialog(caller_callback, no_dialog)
|
||||
end,
|
||||
},
|
||||
}
|
||||
if self.selected_colections then -- select mode
|
||||
if self.selected_collections then -- select mode
|
||||
buttons = {
|
||||
new_collection_button,
|
||||
{}, -- separator
|
||||
@@ -436,8 +444,8 @@ function FileManagerCollection:showCollListDialog(caller_callback, no_dialog)
|
||||
text = _("Deselect all"),
|
||||
callback = function()
|
||||
UIManager:close(button_dialog)
|
||||
for name in pairs(self.selected_colections) do
|
||||
self.selected_colections[name] = nil
|
||||
for name in pairs(self.selected_collections) do
|
||||
self.selected_collections[name] = nil
|
||||
end
|
||||
self:updateCollListItemTable(true)
|
||||
end,
|
||||
@@ -447,7 +455,7 @@ function FileManagerCollection:showCollListDialog(caller_callback, no_dialog)
|
||||
callback = function()
|
||||
UIManager:close(button_dialog)
|
||||
for name in pairs(ReadCollection.coll) do
|
||||
self.selected_colections[name] = true
|
||||
self.selected_collections[name] = true
|
||||
end
|
||||
self:updateCollListItemTable(true)
|
||||
end,
|
||||
@@ -458,7 +466,7 @@ function FileManagerCollection:showCollListDialog(caller_callback, no_dialog)
|
||||
text = _("Apply selection"),
|
||||
callback = function()
|
||||
UIManager:close(button_dialog)
|
||||
caller_callback()
|
||||
caller_callback(self.selected_collections)
|
||||
self.coll_list.close_callback(true)
|
||||
end,
|
||||
},
|
||||
@@ -523,8 +531,8 @@ function FileManagerCollection:addCollection()
|
||||
local editCallback = function(name)
|
||||
ReadCollection:addCollection(name)
|
||||
local mandatory
|
||||
if self.selected_colections then
|
||||
self.selected_colections[name] = true
|
||||
if self.selected_collections then
|
||||
self.selected_collections[name] = true
|
||||
mandatory = self.checkmark
|
||||
else
|
||||
mandatory = 0
|
||||
@@ -579,6 +587,7 @@ end
|
||||
-- external
|
||||
|
||||
function FileManagerCollection:genAddToCollectionButton(file_or_files, caller_pre_callback, caller_post_callback, button_disabled)
|
||||
local is_single_file = type(file_or_files) == "string"
|
||||
return {
|
||||
text = _("Collections…"),
|
||||
enabled = not button_disabled,
|
||||
@@ -586,17 +595,18 @@ function FileManagerCollection:genAddToCollectionButton(file_or_files, caller_pr
|
||||
if caller_pre_callback then
|
||||
caller_pre_callback()
|
||||
end
|
||||
local caller_callback = function()
|
||||
if type(file_or_files) == "string" then
|
||||
ReadCollection:addRemoveItemMultiple(file_or_files, self.selected_colections)
|
||||
local caller_callback = function(selected_collections)
|
||||
if is_single_file then
|
||||
ReadCollection:addRemoveItemMultiple(file_or_files, selected_collections)
|
||||
else -- selected files
|
||||
ReadCollection:addItemsMultiple(file_or_files, self.selected_colections)
|
||||
ReadCollection:addItemsMultiple(file_or_files, selected_collections)
|
||||
end
|
||||
if caller_post_callback then
|
||||
caller_post_callback()
|
||||
end
|
||||
end
|
||||
self:onShowCollList(file_or_files, caller_callback)
|
||||
-- if selected files, do not checkmark any collection on start
|
||||
self:onShowCollList(is_single_file and file_or_files or {}, caller_callback)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -3,7 +3,6 @@ local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local CheckButton = require("ui/widget/checkbutton")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DocSettings = require("docsettings")
|
||||
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local ReadCollection = require("readcollection")
|
||||
@@ -85,7 +84,7 @@ function FileManagerHistory:updateItemTable()
|
||||
local subtitle = ""
|
||||
if self.search_string then
|
||||
subtitle = T(_("Search results (%1)"), #item_table)
|
||||
elseif self.selected_colections then
|
||||
elseif self.selected_collections then
|
||||
subtitle = T(_("Filtered by collections (%1)"), #item_table)
|
||||
elseif self.filter ~= "all" then
|
||||
subtitle = T(_("Status: %1 (%2)"), filter_text[self.filter]:lower(), #item_table)
|
||||
@@ -109,8 +108,8 @@ function FileManagerHistory:isItemMatch(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.selected_colections then
|
||||
for name in pairs(self.selected_colections) do
|
||||
if self.selected_collections then
|
||||
for name in pairs(self.selected_collections) do
|
||||
if not ReadCollection:isFileInCollection(item.file, name) then
|
||||
return false
|
||||
end
|
||||
@@ -173,7 +172,7 @@ function FileManagerHistory:onMenuHold(item)
|
||||
doc_settings_or_file = DocSettings:open(file)
|
||||
if not self.book_props then
|
||||
local props = doc_settings_or_file:readSetting("doc_props")
|
||||
self.book_props = FileManagerBookInfo.extendProps(props, file)
|
||||
self.book_props = self.ui.bookinfo.extendProps(props, file)
|
||||
self.book_props.has_cover = true
|
||||
end
|
||||
else
|
||||
@@ -203,7 +202,7 @@ function FileManagerHistory:onMenuHold(item)
|
||||
UIManager:close(self.histfile_dialog)
|
||||
-- The item's idx field is tied to the current *view*, so we can only pass it as-is when there's no filtering *at all* involved.
|
||||
local index = item.idx
|
||||
if self._manager.search_string or self._manager.selected_colections or self._manager.filter ~= "all" then
|
||||
if self._manager.search_string or self._manager.selected_collections or self._manager.filter ~= "all" then
|
||||
index = nil
|
||||
end
|
||||
require("readhistory"):removeItem(item, index)
|
||||
@@ -252,7 +251,7 @@ function FileManagerHistory:onShowHist(search_info)
|
||||
self.case_sensitive = search_info.case_sensitive
|
||||
else
|
||||
self.search_string = nil
|
||||
self.selected_colections = nil
|
||||
self.selected_collections = nil
|
||||
end
|
||||
self.filter = G_reader_settings:readSetting("history_filter", "all")
|
||||
self.is_frozen = G_reader_settings:isTrue("history_freeze_finished_books")
|
||||
@@ -291,7 +290,7 @@ function FileManagerHistory:showHistDialog()
|
||||
self.filter = filter
|
||||
if filter == "all" then -- reset all filters
|
||||
self.search_string = nil
|
||||
self.selected_colections = nil
|
||||
self.selected_collections = nil
|
||||
end
|
||||
self:updateItemTable()
|
||||
end,
|
||||
@@ -312,11 +311,11 @@ function FileManagerHistory:showHistDialog()
|
||||
text = _("Filter by collections"),
|
||||
callback = function()
|
||||
UIManager:close(hist_dialog)
|
||||
local caller_callback = function()
|
||||
self.selected_colections = self.ui.collections.selected_colections
|
||||
local caller_callback = function(selected_collections)
|
||||
self.selected_collections = selected_collections
|
||||
self:updateItemTable()
|
||||
end
|
||||
self.ui.collections:onShowCollList({}, caller_callback, true) -- do not select any, no dialog to apply
|
||||
self.ui.collections:onShowCollList(self.selected_collections or {}, caller_callback, true) -- no dialog to apply
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ local datetime = require("datetime")
|
||||
local Device = require("device")
|
||||
local DocSettings = require("docsettings")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local Event = require("ui/event")
|
||||
local FileManagerShortcuts = require("apps/filemanager/filemanagershortcuts")
|
||||
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
||||
local Menu = require("ui/widget/menu")
|
||||
@@ -505,11 +506,11 @@ function FileChooser:refreshPath()
|
||||
if self.focused_path then
|
||||
itemmatch = {path = self.focused_path}
|
||||
-- We use focused_path only once, but remember it
|
||||
-- for CoverBrower to re-apply it on startup if needed
|
||||
-- for CoverBrowser to re-apply it on startup if needed
|
||||
self.prev_focused_path = self.focused_path
|
||||
self.focused_path = nil
|
||||
end
|
||||
local subtitle = BD.directory(filemanagerutil.abbreviate(self.path))
|
||||
local subtitle = self.filemanager == nil and BD.directory(filemanagerutil.abbreviate(self.path))
|
||||
self:switchItemTable(nil, self:genItemTableFromPath(self.path), self.path_items[self.path], itemmatch, subtitle)
|
||||
end
|
||||
|
||||
@@ -535,7 +536,9 @@ function FileChooser:changeToPath(path, focused_path)
|
||||
end
|
||||
|
||||
self:refreshPath()
|
||||
self:onPathChanged(path)
|
||||
if self.filemanager then
|
||||
self.filemanager:handleEvent(Event:new("PathChanged", path))
|
||||
end
|
||||
end
|
||||
|
||||
function FileChooser:goHome()
|
||||
@@ -609,10 +612,6 @@ function FileChooser:onFileHold(item)
|
||||
return true
|
||||
end
|
||||
|
||||
function FileChooser:onPathChanged(path)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Used in ReaderStatus:onOpenNextDocumentInFolder().
|
||||
function FileChooser:getNextFile(curr_file)
|
||||
local show_finished = FileChooser.show_finished
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
This module contains miscellaneous helper functions for the KOReader frontend.
|
||||
]]
|
||||
|
||||
local BaseUtil = require("ffi/util")
|
||||
local Utf8Proc = require("ffi/utf8proc")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local md5 = require("ffi/sha2").md5
|
||||
local _ = require("gettext")
|
||||
local C_ = _.pgettext
|
||||
local T = BaseUtil.template
|
||||
local T = ffiUtil.template
|
||||
|
||||
local lshift = bit.lshift
|
||||
local rshift = bit.rshift
|
||||
@@ -489,7 +489,7 @@ function util.splitToChars(text)
|
||||
local hi_surrogate
|
||||
local hi_surrogate_uchar
|
||||
for uchar in text:gmatch(util.UTF8_CHAR_PATTERN) do
|
||||
charcode = BaseUtil.utf8charcode(uchar)
|
||||
charcode = ffiUtil.utf8charcode(uchar)
|
||||
-- (not sure why we need this prevcharcode check; we could get
|
||||
-- charcode=nil with invalid UTF-8, but should we then really
|
||||
-- ignore the following charcode ?)
|
||||
@@ -530,7 +530,7 @@ function util.isCJKChar(c)
|
||||
if #c < 3 then
|
||||
return false
|
||||
end
|
||||
local code = BaseUtil.utf8charcode(c)
|
||||
local code = ffiUtil.utf8charcode(c)
|
||||
-- The weird bracketing is intentional -- we use the lowest possible
|
||||
-- codepoint as a shortcut so if the codepoint is below U+1100 we
|
||||
-- immediately return false.
|
||||
@@ -894,7 +894,7 @@ function util.removePath(path)
|
||||
return nil, "Encountered a component that isn't a directory" .. " (removing `" .. component .. "` for `" .. path .. "`)"
|
||||
end
|
||||
|
||||
local parent = BaseUtil.dirname(component)
|
||||
local parent = ffiUtil.dirname(component)
|
||||
component = parent
|
||||
until parent == "." or parent == "/"
|
||||
return true, nil
|
||||
@@ -988,7 +988,7 @@ function util.getSafeFilename(str, path, limit, limit_ext)
|
||||
limit_ext = limit_ext or 10
|
||||
|
||||
-- Always assume the worst on Android (#7837)
|
||||
if path and not BaseUtil.isAndroid() then
|
||||
if path and not ffiUtil.isAndroid() then
|
||||
local file_system = util.getFilesystemType(path)
|
||||
if file_system ~= "vfat" and file_system ~= "fuse.fsp" then
|
||||
replaceFunc = replaceSlashChar
|
||||
@@ -1140,11 +1140,11 @@ function util.writeToFile(data, filepath, force_flush, lua_dofile_ready, directo
|
||||
end
|
||||
file:write(data)
|
||||
if force_flush then
|
||||
BaseUtil.fsyncOpenedFile(file)
|
||||
ffiUtil.fsyncOpenedFile(file)
|
||||
end
|
||||
file:close()
|
||||
if directory_updated then
|
||||
BaseUtil.fsyncDirectory(filepath)
|
||||
ffiUtil.fsyncDirectory(filepath)
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -1512,6 +1512,7 @@ end
|
||||
-- @treturn table Text char list
|
||||
-- @treturn table Search string char list
|
||||
function util.stringSearch(txt, str, case_sensitive, start_pos)
|
||||
start_pos = start_pos or 1
|
||||
if not case_sensitive then
|
||||
str = Utf8Proc.lowercase(util.fixUtf8(str, "?"))
|
||||
end
|
||||
|
||||
@@ -161,10 +161,11 @@ function Profiles:getSubMenuItems()
|
||||
},
|
||||
self:genAutoExecMenuItem(_("on KOReader start"), "Start", k),
|
||||
self:genAutoExecMenuItem(_("on wake-up"), "Resume", k),
|
||||
self:genAutoExecMenuItem(_("on rotation"), "SetRotationMode", k, true),
|
||||
self:genAutoExecMenuItem(_("on rotation"), "SetRotationMode", k),
|
||||
self:genAutoExecMenuItem(_("on showing folder"), "PathChanged", k, true),
|
||||
-- separator
|
||||
self:genAutoExecMenuItem(_("on book opening"), "ReaderReadyAll", k),
|
||||
self:genAutoExecMenuItem(_("on book closing"), "CloseDocument", k),
|
||||
self:genAutoExecMenuItem(_("on book closing"), "CloseDocumentAll", k),
|
||||
}
|
||||
end,
|
||||
hold_callback = function(touchmenu_instance)
|
||||
@@ -464,8 +465,10 @@ end
|
||||
function Profiles:genAutoExecMenuItem(text, event, profile_name, separator)
|
||||
if event == "SetRotationMode" then
|
||||
return self:genAutoExecSetRotationModeMenuItem(text, event, profile_name, separator)
|
||||
elseif event == "ReaderReadyAll" then
|
||||
return self:genAutoExecReaderReadyAllMenuItem(text, event, profile_name, separator)
|
||||
elseif event == "PathChanged" then
|
||||
return self:genAutoExecPathChangedMenuItem(text, event, profile_name, separator)
|
||||
elseif event == "ReaderReadyAll" or event == "CloseDocumentAll" then
|
||||
return self:genAutoExecDocConditionalMenuItem(text, event, profile_name, separator)
|
||||
end
|
||||
return {
|
||||
text = text,
|
||||
@@ -477,8 +480,9 @@ function Profiles:genAutoExecMenuItem(text, event, profile_name, separator)
|
||||
util.tableRemoveValue(self.autoexec, event, profile_name)
|
||||
else
|
||||
util.tableSetValue(self.autoexec, true, event, profile_name)
|
||||
if event == "ReaderReady" then -- "always" is checked, clear all conditional triggers
|
||||
util.tableRemoveValue(self.autoexec, "ReaderReadyAll", profile_name)
|
||||
if event == "ReaderReady" or event == "CloseDocument" then
|
||||
-- "always" is checked, clear all conditional triggers
|
||||
util.tableRemoveValue(self.autoexec, event .. "All", profile_name)
|
||||
end
|
||||
end
|
||||
end,
|
||||
@@ -520,8 +524,84 @@ function Profiles:genAutoExecSetRotationModeMenuItem(text, event, profile_name,
|
||||
}
|
||||
end
|
||||
|
||||
function Profiles:genAutoExecReaderReadyAllMenuItem(text, event, profile_name, separator)
|
||||
local event_always = "ReaderReady"
|
||||
function Profiles:genAutoExecPathChangedMenuItem(text, event, profile_name, separator)
|
||||
return {
|
||||
text = text,
|
||||
checked_func = function()
|
||||
return util.tableGetValue(self.autoexec, event, profile_name) and true
|
||||
end,
|
||||
sub_item_table_func = function()
|
||||
local conditions = {
|
||||
{ _("if folder path contains"), "has" },
|
||||
{ _("if folder path does not contain"), "has_not" },
|
||||
}
|
||||
local sub_item_table = {}
|
||||
for i, mode in ipairs(conditions) do
|
||||
sub_item_table[i] = {
|
||||
text_func = function()
|
||||
local txt = conditions[i][1]
|
||||
local value = util.tableGetValue(self.autoexec, event, profile_name, conditions[i][2])
|
||||
return value and txt .. ": " .. value or txt
|
||||
end,
|
||||
checked_func = function()
|
||||
return util.tableGetValue(self.autoexec, event, profile_name, conditions[i][2])
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local condition = conditions[i][2]
|
||||
local dialog
|
||||
local buttons = {{
|
||||
{
|
||||
text = _("Current folder"),
|
||||
callback = function()
|
||||
local curr_path = self.ui.file_chooser and self.ui.file_chooser.path or self.ui:getLastDirFile()
|
||||
dialog:addTextToInput(curr_path)
|
||||
end,
|
||||
},
|
||||
}}
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = _("Cancel"),
|
||||
id = "close",
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Save"),
|
||||
callback = function()
|
||||
local txt = dialog:getInputText()
|
||||
if txt == "" then
|
||||
util.tableRemoveValue(self.autoexec, event, profile_name, condition)
|
||||
else
|
||||
util.tableSetValue(self.autoexec, txt, event, profile_name, condition)
|
||||
end
|
||||
UIManager:close(dialog)
|
||||
touchmenu_instance:updateItems()
|
||||
end,
|
||||
},
|
||||
})
|
||||
dialog = InputDialog:new{
|
||||
title = _("Enter text contained in folder path"),
|
||||
input = util.tableGetValue(self.autoexec, event, profile_name, condition),
|
||||
buttons = buttons,
|
||||
}
|
||||
UIManager:show(dialog)
|
||||
dialog:onShowKeyboard()
|
||||
end,
|
||||
}
|
||||
end
|
||||
return sub_item_table
|
||||
end,
|
||||
hold_callback = function(touchmenu_instance)
|
||||
util.tableRemoveValue(self.autoexec, event, profile_name)
|
||||
touchmenu_instance:updateItems()
|
||||
end,
|
||||
separator = separator,
|
||||
}
|
||||
end
|
||||
|
||||
function Profiles:genAutoExecDocConditionalMenuItem(text, event, profile_name, separator)
|
||||
local event_always = event:gsub("All", "")
|
||||
return {
|
||||
text = text,
|
||||
checked_func = function()
|
||||
@@ -532,6 +612,7 @@ function Profiles:genAutoExecReaderReadyAllMenuItem(text, event, profile_name, s
|
||||
{ _("if device orientation is"), "orientation" },
|
||||
{ _("if book metadata contains"), "doc_props" },
|
||||
{ _("if book file path contains"), "filepath" },
|
||||
{ _("if book is in collections"), "collections" },
|
||||
}
|
||||
local sub_item_table = {
|
||||
self:genAutoExecMenuItem(_("always"), event_always, profile_name, true),
|
||||
@@ -706,6 +787,42 @@ function Profiles:genAutoExecReaderReadyAllMenuItem(text, event, profile_name, s
|
||||
touchmenu_instance:updateItems()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text_func = function() -- collections
|
||||
local txt = conditions[4][1]
|
||||
local collections = util.tableGetValue(self.autoexec, event, profile_name, conditions[4][2])
|
||||
if collections then
|
||||
local collections_nb = util.tableSize(collections)
|
||||
return txt .. ": " ..
|
||||
(collections_nb == 1 and self.ui.collections:getCollectionTitle(next(collections))
|
||||
or "(" .. collections_nb .. ")")
|
||||
end
|
||||
return txt
|
||||
end,
|
||||
enabled_func = function()
|
||||
return not util.tableGetValue(self.autoexec, event_always, profile_name)
|
||||
end,
|
||||
checked_func = function()
|
||||
return util.tableGetValue(self.autoexec, event, profile_name, conditions[4][2]) and true
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local condition = conditions[4][2]
|
||||
local collections = util.tableGetValue(self.autoexec, event, profile_name, condition)
|
||||
local caller_callback = function(selected_collections)
|
||||
if next(selected_collections) == nil then
|
||||
util.tableRemoveValue(self.autoexec, event, profile_name, condition)
|
||||
else
|
||||
util.tableSetValue(self.autoexec, selected_collections, event, profile_name, condition)
|
||||
end
|
||||
touchmenu_instance:updateItems()
|
||||
end
|
||||
self.ui.collections:onShowCollList(collections or {}, caller_callback, true)
|
||||
end,
|
||||
hold_callback = function(touchmenu_instance)
|
||||
util.tableRemoveValue(self.autoexec, event, profile_name, conditions[4][2])
|
||||
touchmenu_instance:updateItems()
|
||||
end,
|
||||
},
|
||||
}
|
||||
return sub_item_table
|
||||
end,
|
||||
@@ -729,16 +846,39 @@ function Profiles:onResume() -- global
|
||||
self:executeAutoExecEvent("Resume")
|
||||
end
|
||||
|
||||
function Profiles:onSetRotationMode(rotation) -- global
|
||||
function Profiles:onSetRotationMode(mode) -- global
|
||||
local event = "SetRotationMode"
|
||||
if self.autoexec[event] then
|
||||
for profile_name, modes in pairs(self.autoexec[event]) do
|
||||
if modes[rotation] then
|
||||
if self.ui.config then -- close bottom menu to let Dispatcher execute profile
|
||||
self.ui.config:onCloseConfigMenu()
|
||||
end
|
||||
self:executeAutoExec(profile_name)
|
||||
if self.autoexec[event] == nil then return end
|
||||
for profile_name, modes in pairs(self.autoexec[event]) do
|
||||
if modes[mode] then
|
||||
if self.ui.config then -- close bottom menu to let Dispatcher execute profile
|
||||
self.ui.config:onCloseConfigMenu()
|
||||
end
|
||||
self:executeAutoExec(profile_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Profiles:onPathChanged(path) -- global
|
||||
local event = "PathChanged"
|
||||
if self.autoexec[event] == nil then return end
|
||||
local function is_match(txt, pattern)
|
||||
for str in util.gsplit(pattern, ",") do -- comma separated patterns are allowed
|
||||
if util.stringSearch(txt, str) ~= 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
for profile_name, conditions in pairs(self.autoexec[event]) do
|
||||
local do_execute
|
||||
if conditions.has then
|
||||
do_execute = is_match(path, conditions.has)
|
||||
end
|
||||
if do_execute == nil and conditions.has_not then
|
||||
do_execute = not is_match(path, conditions.has_not)
|
||||
end
|
||||
if do_execute then
|
||||
self:executeAutoExec(profile_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -746,21 +886,21 @@ end
|
||||
function Profiles:onReaderReady() -- global
|
||||
if not self.ui.reloading then
|
||||
self:executeAutoExecEvent("ReaderReady")
|
||||
self:executeAutoExecReaderReadyAll()
|
||||
self:executeAutoExecDocConditional("ReaderReadyAll")
|
||||
end
|
||||
end
|
||||
|
||||
function Profiles:onCloseDocument() -- global
|
||||
if not self.ui.reloading then
|
||||
self:executeAutoExecEvent("CloseDocument")
|
||||
self:executeAutoExecDocConditional("CloseDocumentAll")
|
||||
end
|
||||
end
|
||||
|
||||
function Profiles:executeAutoExecEvent(event)
|
||||
if self.autoexec[event] then
|
||||
for profile_name in pairs(self.autoexec[event]) do
|
||||
self:executeAutoExec(profile_name)
|
||||
end
|
||||
if self.autoexec[event] == nil then return end
|
||||
for profile_name in pairs(self.autoexec[event]) do
|
||||
self:executeAutoExec(profile_name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -786,25 +926,24 @@ function Profiles:executeAutoExec(profile_name)
|
||||
end
|
||||
end
|
||||
|
||||
function Profiles:executeAutoExecReaderReadyAll()
|
||||
local event = "ReaderReadyAll"
|
||||
local function is_match(text, pattern)
|
||||
text = text:lower()
|
||||
for str in util.gsplit(pattern, ",") do -- comma separated patterns are allowed
|
||||
if text:find(str:lower()) then
|
||||
function Profiles:executeAutoExecDocConditional(event)
|
||||
if self.autoexec[event] == nil then return end
|
||||
local function is_match(txt, pattern)
|
||||
for str in util.gsplit(pattern, ",") do
|
||||
if util.stringSearch(txt, str) ~= 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.autoexec[event] then
|
||||
for profile_name, conditions in pairs(self.autoexec[event]) do
|
||||
if self.data[profile_name] then
|
||||
local do_execute
|
||||
for condition, trigger in pairs(conditions) do
|
||||
if condition == "orientation" then
|
||||
local mode = Screen:getRotationMode()
|
||||
do_execute = trigger[mode]
|
||||
elseif condition == "doc_props" then
|
||||
for profile_name, conditions in pairs(self.autoexec[event]) do
|
||||
if self.data[profile_name] then
|
||||
local do_execute
|
||||
for condition, trigger in pairs(conditions) do
|
||||
if condition == "orientation" then
|
||||
local mode = Screen:getRotationMode()
|
||||
do_execute = trigger[mode]
|
||||
elseif condition == "doc_props" then
|
||||
if self.ui.document then
|
||||
for prop_name, pattern in pairs(trigger) do
|
||||
local prop = self.ui.doc_props[prop_name == "title" and "display_title" or prop_name]
|
||||
do_execute = is_match(prop, pattern)
|
||||
@@ -812,17 +951,29 @@ function Profiles:executeAutoExecReaderReadyAll()
|
||||
break -- any prop match is enough
|
||||
end
|
||||
end
|
||||
elseif condition == "filepath" then
|
||||
end
|
||||
elseif condition == "filepath" then
|
||||
if self.ui.document then
|
||||
do_execute = is_match(self.ui.document.file, trigger)
|
||||
end
|
||||
if do_execute then
|
||||
break -- execute profile only once
|
||||
elseif condition == "collections" then
|
||||
if self.ui.document then
|
||||
local ReadCollection = require("readcollection")
|
||||
for collection_name in pairs(trigger) do
|
||||
if ReadCollection:isFileInCollection(self.ui.document.file, collection_name) then
|
||||
do_execute = true
|
||||
break -- any collection is enough
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if do_execute then
|
||||
self:executeAutoExec(profile_name)
|
||||
break -- execute profile only once
|
||||
end
|
||||
end
|
||||
if do_execute then
|
||||
self:executeAutoExec(profile_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user