From b0eb0ce0e1ed8e3f65e77d776152a78411eca1b6 Mon Sep 17 00:00:00 2001 From: hius07 <62179190+hius07@users.noreply.github.com> Date: Tue, 4 Oct 2022 04:44:17 -0700 Subject: [PATCH] FileManager: add Select button to the file long-press menu (#9571) --- frontend/apps/filemanager/filemanager.lua | 95 +++++++----- frontend/ui/widget/buttondialogtitle.lua | 13 +- frontend/ui/widget/filechooser.lua | 1 - plugins/coverbrowser.koplugin/covermenu.lua | 155 ++++++++++---------- plugins/coverbrowser.koplugin/main.lua | 10 +- 5 files changed, 147 insertions(+), 127 deletions(-) diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index 4bfa78e46..660133db8 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -181,7 +181,15 @@ function FileManager:setupLayout() local renameFile = function(file) self:renameFile(file) end local setHome = function(path) self:setHome(path) end - function file_chooser:onFileHold(file) -- luacheck: ignore + function file_chooser:onFileHold(file) + if file_manager.select_mode then + file_manager:tapPlus() + else + self:showFileDialog(file) + end + end + + function file_chooser:showFileDialog(file) -- luacheck: ignore local is_file = lfs.attributes(file, "mode") == "file" local is_folder = lfs.attributes(file, "mode") == "directory" local is_not_parent_folder = BaseUtil.basename(file) ~= ".." @@ -204,19 +212,14 @@ function FileManager:setupLayout() end, }, { - text = _("Reset settings"), - enabled = is_file and DocSettings:hasSidecarFile(BaseUtil.realpath(file)), + text = _("Select"), callback = function() - UIManager:show(ConfirmBox:new{ - text = T(_("Reset settings for this document?\n\n%1\n\nAny highlights or bookmarks will be permanently lost."), BD.filepath(file)), - ok_text = _("Reset"), - ok_callback = function() - filemanagerutil.purgeSettings(file) - require("readhistory"):fileSettingsPurged(file) - self:refreshPath() - UIManager:close(self.file_dialog) - end, - }) + UIManager:close(self.file_dialog) + file_manager:onToggleSelectMode(true) -- no full screen refresh + if is_file then + file_manager.selected_files[file] = true + self:refreshPath() + end end, }, }, @@ -327,6 +330,43 @@ function FileManager:setupLayout() end if is_file then + table.insert(buttons, { + { + text = _("Reset settings"), + id = "reset_settings", -- used by covermenu + enabled = is_file and DocSettings:hasSidecarFile(BaseUtil.realpath(file)), + callback = function() + UIManager:show(ConfirmBox:new{ + text = T(_("Reset settings for this document?\n\n%1\n\nAny highlights or bookmarks will be permanently lost."), BD.filepath(file)), + ok_text = _("Reset"), + ok_callback = function() + filemanagerutil.purgeSettings(file) + require("readhistory"):fileSettingsPurged(file) + self:refreshPath() + UIManager:close(self.file_dialog) + end, + }) + end, + }, + { + text_func = function() + if ReadCollection:checkItemExist(file) then + return _("Remove from favorites") + else + return _("Add to favorites") + end + end, + enabled = DocumentRegistry:getProviders(file) ~= nil, + callback = function() + if ReadCollection:checkItemExist(file) then + ReadCollection:removeItem(file) + else + ReadCollection:addItem(file) + end + UIManager:close(self.file_dialog) + end, + }, + }) table.insert(buttons, { { text = _("Open with…"), @@ -353,6 +393,7 @@ function FileManager:setupLayout() }, { text = _("Book information"), + id = "book_information", -- used by covermenu enabled = FileManagerBookInfo:isSupported(file), callback = function() FileManagerBookInfo:show(file) @@ -360,26 +401,6 @@ function FileManager:setupLayout() end, } }) - table.insert(buttons, { - { - text_func = function() - if ReadCollection:checkItemExist(file) then - return _("Remove from favorites") - else - return _("Add to favorites") - end - end, - enabled = DocumentRegistry:getProviders(file) ~= nil, - callback = function() - if ReadCollection:checkItemExist(file) then - ReadCollection:removeItem(file) - else - ReadCollection:addItem(file) - end - UIManager:close(self.file_dialog) - end, - }, - }) if FileManagerConverter:isSupported(file) then table.insert(buttons, { { @@ -556,12 +577,14 @@ function FileManager:onShowPlusMenu() return true end -function FileManager:onToggleSelectMode() +function FileManager:onToggleSelectMode(no_refresh) logger.dbg("toggle select mode") self.select_mode = not self.select_mode self.selected_files = self.select_mode and {} or nil self.title_bar:setRightIcon(self.select_mode and "check" or "plus") - self:onRefresh() + if not no_refresh then + self:onRefresh() + end end function FileManager:tapPlus() @@ -684,7 +707,7 @@ function FileManager:tapPlus() { text = _("Select files"), callback = function() - self:onToggleSelectMode() + self:onToggleSelectMode(true) -- no full screen refresh UIManager:close(self.file_dialog) end, }, diff --git a/frontend/ui/widget/buttondialogtitle.lua b/frontend/ui/widget/buttondialogtitle.lua index 7156a6b9d..81945a68b 100644 --- a/frontend/ui/widget/buttondialogtitle.lua +++ b/frontend/ui/widget/buttondialogtitle.lua @@ -63,6 +63,12 @@ function ButtonDialogTitle:init() } end end + self.button_table = ButtonTable:new{ + width = self.width, + buttons = self.buttons, + zero_sep = true, + show_parent = self, + } self[1] = CenterContainer:new{ dimen = Screen:getSize(), MovableContainer:new{ @@ -81,12 +87,7 @@ function ButtonDialogTitle:init() }, }, VerticalSpan:new{ width = Size.span.vertical_default }, - ButtonTable:new{ - width = self.width, - buttons = self.buttons, - zero_sep = true, - show_parent = self, - }, + self.button_table, }, background = Blitbuffer.COLOR_WHITE, bordersize = Size.border.window, diff --git a/frontend/ui/widget/filechooser.lua b/frontend/ui/widget/filechooser.lua index b56ca8add..b71222adf 100644 --- a/frontend/ui/widget/filechooser.lua +++ b/frontend/ui/widget/filechooser.lua @@ -476,7 +476,6 @@ function FileChooser:onMenuSelect(item) end function FileChooser:onMenuHold(item) - if self.filemanager and self.filemanager.select_mode then return true end self:onFileHold(item.path) return true end diff --git a/plugins/coverbrowser.koplugin/covermenu.lua b/plugins/coverbrowser.koplugin/covermenu.lua index c0f7a2e8d..c270974e2 100644 --- a/plugins/coverbrowser.koplugin/covermenu.lua +++ b/plugins/coverbrowser.koplugin/covermenu.lua @@ -195,32 +195,32 @@ function CoverMenu:updateItems(select_number) UIManager:scheduleIn(1, self.items_update_action) end - -- (We may not need to do the following if we extend onFileHold + -- (We may not need to do the following if we extend showFileDialog -- code in filemanager.lua to check for existence and call a -- method: self:getAdditionalButtons() to add our buttons -- to its own set.) - -- We want to add some buttons to the onFileHold popup. This function + -- We want to add some buttons to the showFileDialog popup. This function -- is dynamically created by FileManager:init(), and we don't want - -- to override this... So, here, when we see the onFileHold function, + -- to override this... So, here, when we see the showFileDialog function, -- we replace it by ours. - -- (FileManager may replace file_chooser.onFileHold after we've been called once, so we need + -- (FileManager may replace file_chooser.showFileDialog after we've been called once, so we need -- to replace it again if it is not ours) - if not self.onFileHold_ours -- never replaced - or self.onFileHold ~= self.onFileHold_ours then -- it is no more ours + if not self.showFileDialog_ours -- never replaced + or self.showFileDialog ~= self.showFileDialog_ours then -- it is no more ours -- We need to do it at nextTick, once FileManager has instantiated -- its FileChooser completely UIManager:nextTick(function() -- Store original function, so we can call it - self.onFileHold_orig = self.onFileHold + self.showFileDialog_orig = self.showFileDialog -- Replace it with ours -- This causes luacheck warning: "shadowing upvalue argument 'self' on line 34". - -- Ignoring it (as done in filemanager.lua for the same onFileHold) - self.onFileHold = function(self, file) -- luacheck: ignore + -- Ignoring it (as done in filemanager.lua for the same showFileDialog) + self.showFileDialog = function(self, file) -- luacheck: ignore -- Call original function: it will create a ButtonDialogTitle -- and store it as self.file_dialog, and UIManager:show() it. - self.onFileHold_orig(self, file) + self.showFileDialog_orig(self, file) local bookinfo = BookInfoManager:getBookInfo(file) if not bookinfo or bookinfo._is_directory then @@ -238,15 +238,10 @@ function CoverMenu:updateItems(select_number) -- And clear the rendering stack to avoid inheriting its dirty/refresh queue UIManager:clearRenderStack() - -- Replace Book information callback to use directly our bookinfo - orig_buttons[4][2].callback = function() - FileManagerBookInfo:show(file, bookinfo) - UIManager:close(self.file_dialog) - end - - -- Fudge the "Reset settings" button ([1][3]) callback to also trash the cover_info_cache - local orig_purge_callback = orig_buttons[1][3].callback - orig_buttons[1][3].callback = function() + -- Fudge the "Reset settings" button callback to also trash the cover_info_cache + local button = self.file_dialog.button_table:getButtonById("reset_settings") + local orig_purge_callback = button.callback + button.callback = function() -- Wipe the cache if self.cover_info_cache and self.cover_info_cache[file] then self.cover_info_cache[file] = nil @@ -255,63 +250,14 @@ function CoverMenu:updateItems(select_number) orig_purge_callback() end - -- Add some new buttons to original buttons set - table.insert(orig_buttons[5], 1, - { -- Mark the book as read/unread - text_func = function() - -- If the book has a cache entry, it means it has a sidecar file, and it *may* have the info we need. - local status - if self.cover_info_cache and self.cover_info_cache[file] then - local _, _, c_status = unpack(self.cover_info_cache[file]) - status = c_status - end - -- NOTE: status may still be nil if the BookStatus widget was never opened in this book. - -- For our purposes, we assume this means reading or on hold, which is just fine. - -- NOTE: This also means we assume "on hold" means reading, meaning it'll be flipped to "finished", - -- which I'm personally okay with, too. - -- c.f., BookStatusWidget:generateSwitchGroup for the three possible constant values. - return status == "complete" and _("Mark as reading") or _("Mark as read") - end, - enabled = true, - callback = function() - local status - if self.cover_info_cache and self.cover_info_cache[file] then - local c_pages, c_percent_finished, c_status = unpack(self.cover_info_cache[file]) - status = c_status == "complete" and "reading" or "complete" - -- Update the cache, even if it had a nil status before - self.cover_info_cache[file] = {c_pages, c_percent_finished, status} - else - -- We assumed earlier an empty status meant "reading", so, flip that to "complete" - status = "complete" - end - - -- In case the book doesn't have a sidecar file, this'll create it - local docinfo = DocSettings:open(file) - if docinfo.data.summary and docinfo.data.summary.status then - -- Book already had the full BookStatus table in its sidecar, easy peasy! - docinfo.data.summary.status = status - else - -- No BookStatus table, create a minimal one... - if docinfo.data.summary then - -- Err, a summary table with no status entry? Should never happen... - local summary = { status = status } - -- Append the status entry to the existing summary... - util.tableMerge(docinfo.data.summary, summary) - else - -- No summary table at all, create a minimal one - local summary = { status = status } - docinfo:saveSetting("summary", summary) - end - end - docinfo:flush() - - UIManager:close(self.file_dialog) - self:updateItems() - end, - } - ) + -- Replace the "Book information" button callback to use directly our bookinfo + button = self.file_dialog.button_table:getButtonById("book_information") + button.callback = function() + FileManagerBookInfo:show(file, bookinfo) + UIManager:close(self.file_dialog) + end - -- Keep on adding new buttons + -- Add some new buttons to original buttons set table.insert(orig_buttons, { { -- Allow user to view real size cover in ImageViewer text = _("View full size cover"), @@ -379,8 +325,59 @@ function CoverMenu:updateItems(select_number) }, }) table.insert(orig_buttons, { + { -- Mark the book as read/unread + text_func = function() + -- If the book has a cache entry, it means it has a sidecar file, and it *may* have the info we need. + local status + if self.cover_info_cache and self.cover_info_cache[file] then + local _, _, c_status = unpack(self.cover_info_cache[file]) + status = c_status + end + -- NOTE: status may still be nil if the BookStatus widget was never opened in this book. + -- For our purposes, we assume this means reading or on hold, which is just fine. + -- NOTE: This also means we assume "on hold" means reading, meaning it'll be flipped to "finished", + -- which I'm personally okay with, too. + -- c.f., BookStatusWidget:generateSwitchGroup for the three possible constant values. + return status == "complete" and _("Mark as reading") or _("Mark as read") + end, + callback = function() + local status + if self.cover_info_cache and self.cover_info_cache[file] then + local c_pages, c_percent_finished, c_status = unpack(self.cover_info_cache[file]) + status = c_status == "complete" and "reading" or "complete" + -- Update the cache, even if it had a nil status before + self.cover_info_cache[file] = {c_pages, c_percent_finished, status} + else + -- We assumed earlier an empty status meant "reading", so, flip that to "complete" + status = "complete" + end + + -- In case the book doesn't have a sidecar file, this'll create it + local docinfo = DocSettings:open(file) + if docinfo.data.summary and docinfo.data.summary.status then + -- Book already had the full BookStatus table in its sidecar, easy peasy! + docinfo.data.summary.status = status + else + -- No BookStatus table, create a minimal one... + if docinfo.data.summary then + -- Err, a summary table with no status entry? Should never happen... + local summary = { status = status } + -- Append the status entry to the existing summary... + util.tableMerge(docinfo.data.summary, summary) + else + -- No summary table at all, create a minimal one + local summary = { status = status } + docinfo:saveSetting("summary", summary) + end + end + docinfo:flush() + + UIManager:close(self.file_dialog) + self:updateItems() + end, + }, { -- Allow a new extraction (multiple interruptions, book replaced)... - text = _("Refresh cached book information"), + text = _("Refresh book info"), enabled = bookinfo and true or false, callback = function() -- Wipe the cache @@ -406,13 +403,13 @@ function CoverMenu:updateItems(select_number) end -- Remember our function - self.onFileHold_ours = self.onFileHold + self.showFileDialog_ours = self.showFileDialog end) end Menu.mergeTitleBarIntoLayout(self) end --- Similar to onFileHold setup just above, but for History, +-- Similar to showFileDialog setup just above, but for History, -- which is plugged in main.lua _FileManagerHistory_updateItemTable() function CoverMenu:onHistoryMenuHold(item) -- Call original function: it will create a ButtonDialog @@ -531,7 +528,7 @@ function CoverMenu:onHistoryMenuHold(item) return true end --- Similar to onFileHold setup just above, but for Collections, +-- Similar to showFileDialog setup just above, but for Collections, -- which is plugged in main.lua _FileManagerCollections_updateItemTable() function CoverMenu:onCollectionsMenuHold(item) -- Call original function: it will create a ButtonDialog diff --git a/plugins/coverbrowser.koplugin/main.lua b/plugins/coverbrowser.koplugin/main.lua index 7ec3e6e4c..fcdce23d8 100644 --- a/plugins/coverbrowser.koplugin/main.lua +++ b/plugins/coverbrowser.koplugin/main.lua @@ -467,11 +467,11 @@ function CoverBrowser:refreshFileManagerInstance(cleanup, post_init) 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 + if fc.showFileDialog_orig then + -- remove our showFileDialog that extended file_dialog with new buttons + fc.showFileDialog = fc.showFileDialog_orig + fc.showFileDialog_orig = nil + fc.showFileDialog_ours = nil end end if filemanager_display_mode then