mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Made the onHold buttons table similar to the one of File browser. Added "Purge .sdr" and "Delete" to these buttons. Moved the purgeSettings and removeFileFromHistoryIfWanted logic into filemanagerutil functions. Stay on the same page when manipulating history (previously, we were always put back on first page). Really keep deleted files in history (unless setting says otherwise). Show deleted files in grey or dimmed in classic History and all CoverBrowser display modes.
545 lines
26 KiB
Lua
545 lines
26 KiB
Lua
local Device = require("device")
|
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local UIManager = require("ui/uimanager")
|
|
local logger = require("logger")
|
|
local _ = require("gettext")
|
|
local BookInfoManager = require("bookinfomanager")
|
|
|
|
--[[
|
|
This plugin provides additional display modes to file browsers (File Manager
|
|
and History).
|
|
It does that by dynamically replacing some methods code to their classes
|
|
or instances.
|
|
--]]
|
|
|
|
-- We need to save the original methods early here as locals.
|
|
-- For some reason, saving them as attributes in init() does not allow
|
|
-- us to get back to classic mode
|
|
local FileChooser = require("ui/widget/filechooser")
|
|
local _FileChooser__recalculateDimen_orig = FileChooser._recalculateDimen
|
|
local _FileChooser_updateItems_orig = FileChooser.updateItems
|
|
local _FileChooser_onCloseWidget_orig = FileChooser.onCloseWidget
|
|
local _FileChooser_onSwipe_orig = FileChooser.onSwipe
|
|
|
|
local FileManagerHistory = require("apps/filemanager/filemanagerhistory")
|
|
local _FileManagerHistory_updateItemTable_orig = FileManagerHistory.updateItemTable
|
|
|
|
-- Available display modes
|
|
local DISPLAY_MODES = {
|
|
-- nil or "" -- classic : filename only
|
|
mosaic_image = true, -- 3x3 grid covers with images
|
|
mosaic_text = true, -- 3x3 grid covers text only
|
|
list_image_meta = true, -- image with metadata (title/authors)
|
|
list_only_meta = true, -- metadata with no image
|
|
list_image_filename = true, -- image with filename (no metadata)
|
|
}
|
|
|
|
local CoverBrowser = InputContainer:new{}
|
|
|
|
function CoverBrowser:init()
|
|
self.full_featured = true
|
|
-- As we don't know how to run and kill subprocesses on Android (for
|
|
-- background info extraction), this plugin is very limited on Android,
|
|
-- and will provide only a menu for managing a few core settings.
|
|
if Device.isAndroid() then
|
|
self.full_featured = false
|
|
end
|
|
|
|
self.ui.menu:registerToMainMenu(self)
|
|
|
|
if not self.full_featured then
|
|
return
|
|
end
|
|
|
|
self.filemanager_display_mode = BookInfoManager:getSetting("filemanager_display_mode")
|
|
self:setupFileManagerDisplayMode()
|
|
|
|
self.history_display_mode = BookInfoManager:getSetting("history_display_mode")
|
|
self:setupHistoryDisplayMode()
|
|
|
|
-- If KOReader has started directly to FileManager, the FileManager
|
|
-- instance is being init()'ed and there is no FileManager.instance yet,
|
|
-- but there'll be one at next tick.
|
|
UIManager:nextTick(function()
|
|
self:refreshFileManagerInstance()
|
|
end)
|
|
end
|
|
|
|
function CoverBrowser:addToMainMenu(menu_items)
|
|
-- We add it only to FileManager menu
|
|
if self.ui.view then -- Reader
|
|
return
|
|
end
|
|
|
|
-- Items available even if not full_featured
|
|
-- (settings used by core, that fit in this menu)
|
|
local generic_items = {
|
|
{
|
|
text_func = function()
|
|
local current_state = _("Show new files in bold")
|
|
if G_reader_settings:readSetting("show_file_in_bold") == "opened" then
|
|
current_state = _("Show opened files in bold")
|
|
elseif G_reader_settings:readSetting("show_file_in_bold") == false then
|
|
current_state = _("Show files in bold") -- with checkmark unchecked
|
|
end
|
|
if self.full_featured then
|
|
-- Inform that this settings applies only to classic file chooser
|
|
current_state = _("(Classic mode) ") .. current_state
|
|
end
|
|
return current_state
|
|
end,
|
|
checked_func = function() return G_reader_settings:readSetting("show_file_in_bold") ~= false end,
|
|
sub_item_table = {
|
|
{
|
|
text = _("Don't show files in bold"),
|
|
checked_func = function() return G_reader_settings:readSetting("show_file_in_bold") == false end,
|
|
callback = function()
|
|
G_reader_settings:saveSetting("show_file_in_bold", false)
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Show opened files in bold"),
|
|
checked_func = function() return G_reader_settings:readSetting("show_file_in_bold") == "opened" end,
|
|
callback = function()
|
|
G_reader_settings:saveSetting("show_file_in_bold", "opened")
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Show new (not yet opened) files in bold"),
|
|
checked_func = function()
|
|
return G_reader_settings:readSetting("show_file_in_bold") ~= false and G_reader_settings:readSetting("show_file_in_bold") ~= "opened"
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:delSetting("show_file_in_bold")
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
},
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("Shorten home directory to ~"),
|
|
checked_func = function() return G_reader_settings:readSetting("home_dir_display_name") end,
|
|
callback = function()
|
|
if G_reader_settings:readSetting("home_dir_display_name") then
|
|
G_reader_settings:delSetting("home_dir_display_name")
|
|
local FileManager = require("apps/filemanager/filemanager")
|
|
if FileManager.instance then FileManager.instance:reinit() end
|
|
else
|
|
G_reader_settings:saveSetting("home_dir_display_name", "~")
|
|
local FileManager = require("apps/filemanager/filemanager")
|
|
if FileManager.instance then FileManager.instance:reinit() end
|
|
end
|
|
end,
|
|
},
|
|
{
|
|
text = _("Auto-remove deleted or purged items from history"),
|
|
checked_func = function() return G_reader_settings:readSetting("autoremove_deleted_items_from_history") end,
|
|
callback = function() G_reader_settings:flipNilOrFalse("autoremove_deleted_items_from_history") end,
|
|
},
|
|
}
|
|
|
|
if not self.full_featured then
|
|
-- Make the generic items directly as 1st level items,
|
|
-- and use alternate name for main menu, not mentionning
|
|
-- "display mode" that are not available
|
|
menu_items.filemanager_display_mode = {
|
|
text = _("File browser settings"),
|
|
sub_item_table = generic_items
|
|
}
|
|
return
|
|
end
|
|
|
|
menu_items.filemanager_display_mode = {
|
|
text = _("Display mode"),
|
|
sub_item_table = {
|
|
-- selecting these does not close menu, which may be nice
|
|
-- so one can see how they look below the menu
|
|
{
|
|
text = _("Classic (filename only)"),
|
|
checked_func = function() return not self.filemanager_display_mode end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Mosaic with cover images"),
|
|
checked_func = function() return self.filemanager_display_mode == "mosaic_image" end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("mosaic_image")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Mosaic with text covers"),
|
|
checked_func = function() return self.filemanager_display_mode == "mosaic_text" end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("mosaic_text")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with cover images and metadata"),
|
|
checked_func = function() return self.filemanager_display_mode == "list_image_meta" end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("list_image_meta")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with metadata, no images"),
|
|
checked_func = function() return self.filemanager_display_mode == "list_only_meta" end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("list_only_meta")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with cover images and filenames"),
|
|
checked_func = function() return self.filemanager_display_mode == "list_image_filename" end,
|
|
callback = function()
|
|
self:setupFileManagerDisplayMode("list_image_filename")
|
|
end,
|
|
separator = true,
|
|
},
|
|
-- Plug the same choices for History here as a submenu
|
|
-- (Any other suitable place for that ?)
|
|
{
|
|
text = _("History display mode"),
|
|
sub_item_table = {
|
|
{
|
|
text = _("Classic (filename only)"),
|
|
checked_func = function() return not self.history_display_mode end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Mosaic with cover images"),
|
|
checked_func = function() return self.history_display_mode == "mosaic_image" end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("mosaic_image")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Mosaic with text covers"),
|
|
checked_func = function() return self.history_display_mode == "mosaic_text" end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("mosaic_text")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with cover images and metadata"),
|
|
checked_func = function() return self.history_display_mode == "list_image_meta" end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("list_image_meta")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with metadata, no images"),
|
|
checked_func = function() return self.history_display_mode == "list_only_meta" end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("list_only_meta")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Detailed list with cover images and filenames"),
|
|
checked_func = function() return self.history_display_mode == "list_image_filename" end,
|
|
callback = function()
|
|
self:setupHistoryDisplayMode("list_image_filename")
|
|
end,
|
|
separator = true,
|
|
},
|
|
},
|
|
separator = true,
|
|
},
|
|
-- Misc settings
|
|
{
|
|
text = _("Other settings"),
|
|
sub_item_table = {
|
|
{
|
|
text = _("Show hint for books with description"),
|
|
checked_func = function() return not BookInfoManager:getSetting("no_hint_description") end,
|
|
callback = function()
|
|
if BookInfoManager:getSetting("no_hint_description") then
|
|
BookInfoManager:saveSetting("no_hint_description", false)
|
|
else
|
|
BookInfoManager:saveSetting("no_hint_description", true)
|
|
end
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Show hint for opened books in history"),
|
|
checked_func = function() return BookInfoManager:getSetting("history_hint_opened") end,
|
|
callback = function()
|
|
if BookInfoManager:getSetting("history_hint_opened") then
|
|
BookInfoManager:saveSetting("history_hint_opened", false)
|
|
else
|
|
BookInfoManager:saveSetting("history_hint_opened", true)
|
|
end
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Append series metadata to authors"),
|
|
checked_func = function() return BookInfoManager:getSetting("append_series_to_authors") end,
|
|
callback = function()
|
|
if BookInfoManager:getSetting("append_series_to_authors") then
|
|
BookInfoManager:saveSetting("append_series_to_authors", false)
|
|
else
|
|
BookInfoManager:saveSetting("append_series_to_authors", true)
|
|
end
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Append series metadata to title"),
|
|
checked_func = function() return BookInfoManager:getSetting("append_series_to_title") end,
|
|
callback = function()
|
|
if BookInfoManager:getSetting("append_series_to_title") then
|
|
BookInfoManager:saveSetting("append_series_to_title", false)
|
|
else
|
|
BookInfoManager:saveSetting("append_series_to_title", true)
|
|
end
|
|
self:refreshFileManagerInstance()
|
|
end,
|
|
},
|
|
-- generic_items will be inserted here
|
|
},
|
|
},
|
|
{
|
|
text = _("Book info cache management"),
|
|
sub_item_table = {
|
|
{
|
|
text_func = function() -- add current db size to menu text
|
|
local sstr = BookInfoManager:getDbSize()
|
|
return _("Current cache size: ") .. sstr
|
|
end,
|
|
-- no callback, only for information
|
|
},
|
|
{
|
|
text = _("Prune cache of removed books"),
|
|
callback = function()
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
UIManager:close(self.file_dialog)
|
|
UIManager:show(ConfirmBox:new{
|
|
-- Checking file existences is quite fast, but deleting entries is slow.
|
|
text = _("Are you sure that you want to prune cache of removed books?\n(This may take a while.)"),
|
|
ok_text = _("Prune cache"),
|
|
ok_callback = function()
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local msg = InfoMessage:new{ text = _("Pruning cache of removed books…") }
|
|
UIManager:show(msg)
|
|
UIManager:nextTick(function()
|
|
local summary = BookInfoManager:removeNonExistantEntries()
|
|
UIManager:close(msg)
|
|
UIManager:show( InfoMessage:new{ text = summary } )
|
|
end)
|
|
end
|
|
})
|
|
end,
|
|
},
|
|
{
|
|
text = _("Compact cache database"),
|
|
callback = function()
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
UIManager:close(self.file_dialog)
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Are you sure that you want to compact cache database?\n(This may take a while.)"),
|
|
ok_text = _("Compact database"),
|
|
ok_callback = function()
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local msg = InfoMessage:new{ text = _("Compacting cache database…") }
|
|
UIManager:show(msg)
|
|
UIManager:nextTick(function()
|
|
local summary = BookInfoManager:compactDb()
|
|
UIManager:close(msg)
|
|
UIManager:show( InfoMessage:new{ text = summary } )
|
|
end)
|
|
end
|
|
})
|
|
end,
|
|
},
|
|
{
|
|
text = _("Delete cache database"),
|
|
callback = function()
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
UIManager:close(self.file_dialog)
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Are you sure that you want to delete cover and metadata cache?\n(This will also reset your display mode settings.)"),
|
|
ok_text = _("Purge"),
|
|
ok_callback = function()
|
|
BookInfoManager:deleteDb()
|
|
end
|
|
})
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
-- Finally, insert the generic items at end of "Other settings" submenu
|
|
local sub_item_table = menu_items.filemanager_display_mode.sub_item_table
|
|
local generic_items_target = sub_item_table[#sub_item_table-1].sub_item_table -- second to last
|
|
for _, item in pairs(generic_items) do
|
|
table.insert(generic_items_target, item)
|
|
end
|
|
end
|
|
|
|
function CoverBrowser:refreshFileManagerInstance(cleanup)
|
|
local FileManager = require("apps/filemanager/filemanager")
|
|
local fm = FileManager.instance
|
|
if fm then
|
|
local fc = fm.file_chooser
|
|
if cleanup then -- clean instance properties we may have set
|
|
if fc.onFileHold_orig then
|
|
-- remove our onFileHold that extended file_dialog with new buttons
|
|
fc.onFileHold = fc.onFileHold_orig
|
|
fc.onFileHold_orig = nil
|
|
fc.onFileHold_ours = nil
|
|
end
|
|
end
|
|
if self.filemanager_display_mode then
|
|
fc:updateItems()
|
|
else -- classic file_chooser needs this for a full redraw
|
|
fc:refreshPath()
|
|
end
|
|
end
|
|
end
|
|
|
|
function CoverBrowser:setupFileManagerDisplayMode(display_mode)
|
|
if not display_mode then -- if none provided, use current one
|
|
display_mode = self.filemanager_display_mode
|
|
end
|
|
if not DISPLAY_MODES[display_mode] then
|
|
display_mode = nil
|
|
end
|
|
self.filemanager_display_mode = display_mode
|
|
BookInfoManager:saveSetting("filemanager_display_mode", self.filemanager_display_mode)
|
|
logger.dbg("CoverBrowser: setting FileManager display mode to:", display_mode or "classic")
|
|
|
|
if not display_mode then -- classic mode
|
|
-- Put back original methods
|
|
FileChooser.updateItems = _FileChooser_updateItems_orig
|
|
FileChooser.onCloseWidget = _FileChooser_onCloseWidget_orig
|
|
FileChooser.onSwipe = _FileChooser_onSwipe_orig
|
|
FileChooser._recalculateDimen = _FileChooser__recalculateDimen_orig
|
|
-- Also clean-up what we added, even if it does not bother original code
|
|
FileChooser._updateItemsBuildUI = nil
|
|
FileChooser._do_cover_images = nil
|
|
FileChooser._do_filename_only = nil
|
|
FileChooser._do_hint_opened = nil
|
|
self:refreshFileManagerInstance(true)
|
|
return
|
|
end
|
|
|
|
-- In both mosaic and list modes, replace original methods with those from
|
|
-- our generic CoverMenu
|
|
local CoverMenu = require("covermenu")
|
|
FileChooser.updateItems = CoverMenu.updateItems
|
|
FileChooser.onCloseWidget = CoverMenu.onCloseWidget
|
|
FileChooser.onSwipe = CoverMenu.onSwipe
|
|
|
|
if display_mode == "mosaic_image" or display_mode == "mosaic_text" then -- mosaic mode
|
|
-- Replace some other original methods with those from our MosaicMenu
|
|
local MosaicMenu = require("mosaicmenu")
|
|
FileChooser._recalculateDimen = MosaicMenu._recalculateDimen
|
|
FileChooser._updateItemsBuildUI = MosaicMenu._updateItemsBuildUI
|
|
-- Set MosaicMenu behaviour:
|
|
FileChooser._do_cover_images = display_mode ~= "mosaic_text"
|
|
FileChooser._do_hint_opened = true -- dogear at bottom
|
|
-- One could override default 3x3 grid here (put that as settings ?)
|
|
-- FileChooser.nb_cols_portrait = 4
|
|
-- FileChooser.nb_rows_portrait = 4
|
|
-- FileChooser.nb_cols_landscape = 6
|
|
-- FileChooser.nb_rows_landscape = 3
|
|
|
|
elseif display_mode == "list_image_meta" or display_mode == "list_only_meta" or
|
|
display_mode == "list_image_filename" then -- list modes
|
|
-- Replace some other original methods with those from our ListMenu
|
|
local ListMenu = require("listmenu")
|
|
FileChooser._recalculateDimen = ListMenu._recalculateDimen
|
|
FileChooser._updateItemsBuildUI = ListMenu._updateItemsBuildUI
|
|
-- Set ListMenu behaviour:
|
|
FileChooser._do_cover_images = display_mode ~= "list_only_meta"
|
|
FileChooser._do_filename_only = display_mode == "list_image_filename"
|
|
FileChooser._do_hint_opened = true -- dogear at bottom
|
|
end
|
|
|
|
self:refreshFileManagerInstance()
|
|
end
|
|
|
|
local function _FileManagerHistory_updateItemTable(self)
|
|
-- 'self' here is the single FileManagerHistory instance
|
|
-- FileManagerHistory has just created a new instance of Menu as 'hist_menu'
|
|
-- at each display of History. Soon after instantiation, this method
|
|
-- is called. The first time it is called, we replace some methods.
|
|
local display_mode = self.display_mode
|
|
local hist_menu = self.hist_menu
|
|
|
|
if not hist_menu._coverbrowser_overridden then
|
|
hist_menu._coverbrowser_overridden = true
|
|
|
|
-- In both mosaic and list modes, replace original methods with those from
|
|
-- our generic CoverMenu
|
|
local CoverMenu = require("covermenu")
|
|
hist_menu.updateItems = CoverMenu.updateItems
|
|
hist_menu.onCloseWidget = CoverMenu.onCloseWidget
|
|
hist_menu.onSwipe = CoverMenu.onSwipe
|
|
-- Also replace original onMenuHold (it will use original method, so remember it)
|
|
hist_menu.onMenuHold_orig = hist_menu.onMenuHold
|
|
hist_menu.onMenuHold = CoverMenu.onHistoryMenuHold
|
|
|
|
if display_mode == "mosaic_image" or display_mode == "mosaic_text" then -- mosaic mode
|
|
-- Replace some other original methods with those from our MosaicMenu
|
|
local MosaicMenu = require("mosaicmenu")
|
|
hist_menu._recalculateDimen = MosaicMenu._recalculateDimen
|
|
hist_menu._updateItemsBuildUI = MosaicMenu._updateItemsBuildUI
|
|
-- Set MosaicMenu behaviour:
|
|
hist_menu._do_cover_images = display_mode ~= "mosaic_text"
|
|
-- no need for do_hint_opened with History
|
|
|
|
elseif display_mode == "list_image_meta" or display_mode == "list_only_meta" or
|
|
display_mode == "list_image_filename" then -- list modes
|
|
-- Replace some other original methods with those from our ListMenu
|
|
local ListMenu = require("listmenu")
|
|
hist_menu._recalculateDimen = ListMenu._recalculateDimen
|
|
hist_menu._updateItemsBuildUI = ListMenu._updateItemsBuildUI
|
|
-- Set ListMenu behaviour:
|
|
hist_menu._do_cover_images = display_mode ~= "list_only_meta"
|
|
hist_menu._do_filename_only = display_mode == "list_image_filename"
|
|
-- no need for do_hint_opened with History
|
|
|
|
end
|
|
hist_menu._do_hint_opened = BookInfoManager:getSetting("history_hint_opened")
|
|
end
|
|
|
|
-- And do now what the original does
|
|
_FileManagerHistory_updateItemTable_orig(self)
|
|
end
|
|
|
|
function CoverBrowser:setupHistoryDisplayMode(display_mode)
|
|
if not display_mode then -- if none provided, use current one
|
|
display_mode = self.history_display_mode
|
|
end
|
|
if not DISPLAY_MODES[display_mode] then
|
|
display_mode = nil
|
|
end
|
|
self.history_display_mode = display_mode
|
|
BookInfoManager:saveSetting("history_display_mode", self.history_display_mode)
|
|
logger.dbg("CoverBrowser: setting History display mode to:", display_mode or "classic")
|
|
|
|
-- We only need to replace one FileManagerHistory method
|
|
if not display_mode then -- classic mode
|
|
-- Put back original methods
|
|
FileManagerHistory.updateItemTable = _FileManagerHistory_updateItemTable_orig
|
|
FileManagerHistory.display_mode = nil
|
|
else
|
|
-- Replace original method with the one defined above
|
|
FileManagerHistory.updateItemTable = _FileManagerHistory_updateItemTable
|
|
-- And let it know which display_mode we should use
|
|
FileManagerHistory.display_mode = display_mode
|
|
end
|
|
end
|
|
|
|
return CoverBrowser
|