From 88d6613feda7d174f0d096854e4f2373597b01fe Mon Sep 17 00:00:00 2001 From: hius07 <62179190+hius07@users.noreply.github.com> Date: Thu, 16 Nov 2023 07:48:10 +0200 Subject: [PATCH] Folder shortcuts: new markers, buttons (#11108) Buttons to add/remove folder shortcut from Plus menu and from folder popup dialog. A marker ("empty star") for folders with shortcuts. --- frontend/apps/filemanager/filemanager.lua | 82 ++-- frontend/apps/filemanager/filemanagermenu.lua | 6 +- .../apps/filemanager/filemanagershortcuts.lua | 351 ++++++++++-------- frontend/ui/widget/filechooser.lua | 4 + 4 files changed, 240 insertions(+), 203 deletions(-) diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index f0b3627c3..6bbc430a0 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -109,6 +109,15 @@ function FileManager:onSetDimensions(dimen) end end +function FileManager:updateTitleBarPath(path) + path = path or self.file_chooser.path + local text = BD.directory(filemanagerutil.abbreviate(path)) + if FileManagerShortcuts:hasFolderShortcut(path) then + text = "☆ " .. text + end + self.title_bar:setSubTitle(text) +end + function FileManager:setupLayout() self.show_parent = self.show_parent or self self.title_bar = TitleBar:new{ @@ -116,7 +125,7 @@ function FileManager:setupLayout() align = "center", title = self.title, title_top_padding = Screen:scaleBySize(6), - subtitle = BD.directory(filemanagerutil.abbreviate(self.root_path)), + subtitle = "", subtitle_truncate_left = true, subtitle_fullwidth = true, button_padding = Screen:scaleBySize(5), @@ -129,6 +138,7 @@ 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{ -- remember to adjust the height when new item is added to the group @@ -153,7 +163,7 @@ function FileManager:setupLayout() local file_manager = self function file_chooser:onPathChanged(path) -- luacheck: ignore - file_manager.title_bar:setSubTitle(BD.directory(filemanagerutil.abbreviate(path))) + file_manager:updateTitleBarPath(path) return true end @@ -183,6 +193,18 @@ function FileManager:setupLayout() local is_file = lfs.attributes(file, "mode") == "file" local is_folder = lfs.attributes(file, "mode") == "directory" local is_not_parent_folder = BaseUtil.basename(file) ~= ".." + + local function close_dialog_callback() + UIManager:close(self.file_dialog) + end + local function refresh_callback() + self:refreshPath() + end + local function close_dialog_refresh_callback() + UIManager:close(self.file_dialog) + self:refreshPath() + end + local buttons = { { { @@ -227,10 +249,7 @@ function FileManager:setupLayout() enabled = is_not_parent_folder, callback = function() UIManager:close(self.file_dialog) - local function post_delete_callback() - self:refreshPath() - end - file_manager:showDeleteFileDialog(file, post_delete_callback) + file_manager:showDeleteFileDialog(file, refresh_callback) end, }, { @@ -246,19 +265,12 @@ function FileManager:setupLayout() } if is_file then - local function close_dialog_callback() - UIManager:close(self.file_dialog) - end - local function status_button_callback() - UIManager:close(self.file_dialog) - self:refreshPath() -- sidecar folder may be created/deleted - end local has_provider = DocumentRegistry:hasProvider(file) if has_provider or DocSettings:hasSidecarFile(file) then - table.insert(buttons, filemanagerutil.genStatusButtonsRow(file, status_button_callback)) + table.insert(buttons, filemanagerutil.genStatusButtonsRow(file, close_dialog_refresh_callback)) table.insert(buttons, {}) -- separator table.insert(buttons, { - filemanagerutil.genResetSettingsButton(file, status_button_callback), + filemanagerutil.genResetSettingsButton(file, close_dialog_refresh_callback), filemanagerutil.genAddRemoveFavoritesButton(file, close_dialog_callback), }) end @@ -297,15 +309,19 @@ function FileManager:setupLayout() end if is_folder then + local folder = BaseUtil.realpath(file) table.insert(buttons, { { text = _("Set as HOME folder"), callback = function() UIManager:close(self.file_dialog) - file_manager:setHome(BaseUtil.realpath(file)) + file_manager:setHome(folder) end }, }) + table.insert(buttons, { + file_manager.folder_shortcuts:genAddRemoveShortcutButton(folder, close_dialog_callback, refresh_callback) + }) end self.file_dialog = ButtonDialog:new{ @@ -471,6 +487,13 @@ function FileManager:onToggleSelectMode(no_refresh) end function FileManager:tapPlus() + local function close_dialog_callback() + UIManager:close(self.file_dialog) + end + local function refresh_titlebar_callback() + self:updateTitleBarPath() + end + local title, buttons if self.select_mode then local select_count = util.tableSize(self.selected_files) @@ -589,13 +612,7 @@ function FileManager:tapPlus() self:createFolder() end, }, - { - text = _("Folder shortcuts"), - callback = function() - UIManager:close(self.file_dialog) - self:handleEvent(Event:new("ShowFolderShortcutsDialog")) - end - }, + self.folder_shortcuts:genShowFolderShortcutsButton(close_dialog_callback), }, } else @@ -636,7 +653,7 @@ function FileManager:tapPlus() UIManager:close(self.file_dialog) self:setHome(self.file_chooser.path) end - } + }, }, { { @@ -645,7 +662,7 @@ function FileManager:tapPlus() UIManager:close(self.file_dialog) self:goHome() end - } + }, }, { { @@ -654,17 +671,14 @@ function FileManager:tapPlus() UIManager:close(self.file_dialog) self:openRandomFile(self.file_chooser.path) end - } + }, }, { - { - text = _("Folder shortcuts"), - callback = function() - UIManager:close(self.file_dialog) - self:handleEvent(Event:new("ShowFolderShortcutsDialog")) - end - } - } + self.folder_shortcuts:genShowFolderShortcutsButton(close_dialog_callback), + }, + { + self.folder_shortcuts:genAddRemoveShortcutButton(self.file_chooser.path, close_dialog_callback, refresh_titlebar_callback), + }, } if Device:hasExternalSD() then diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index e2bc24651..70a742f33 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -2,7 +2,6 @@ local BD = require("ui/bidi") local CenterContainer = require("ui/widget/container/centercontainer") local ConfirmBox = require("ui/widget/confirmbox") local Device = require("device") -local Event = require("ui/event") local FFIUtil = require("ffi/util") local InputContainer = require("ui/widget/container/inputcontainer") local PluginLoader = require("pluginloader") @@ -359,8 +358,7 @@ function FileManagerMenu:setUpdateItemTable() end, callback = function() G_reader_settings:flipNilOrTrue("shorten_home_dir") - local FileManager = require("apps/filemanager/filemanager") - if FileManager.instance then FileManager.instance:reinit() end + self.ui:updateTitleBarPath() end, help_text = _([[ "Shorten home folder" will display the home folder itself as "Home" instead of its full path. @@ -786,7 +784,7 @@ The sorting order is the same as in filemanager. Tap a book in the search results to open it.]]), callback = function() - self.ui:handleEvent(Event:new("ShowFileSearch")) + self.ui.filesearcher:onShowFileSearch() end } diff --git a/frontend/apps/filemanager/filemanagershortcuts.lua b/frontend/apps/filemanager/filemanagershortcuts.lua index 83f6dc3bc..6d8e945fd 100644 --- a/frontend/apps/filemanager/filemanagershortcuts.lua +++ b/frontend/apps/filemanager/filemanagershortcuts.lua @@ -7,199 +7,210 @@ local Screen = require("device").screen local UIManager = require("ui/uimanager") local WidgetContainer = require("ui/widget/container/widgetcontainer") local lfs = require("libs/libkoreader-lfs") -local util = require("ffi/util") local _ = require("gettext") -local T = util.template local FileManagerShortcuts = WidgetContainer:extend{ + title = _("Folder shortcuts"), folder_shortcuts = G_reader_settings:readSetting("folder_shortcuts", {}), } -function FileManagerShortcuts:updateItemTable(select_callback) +function FileManagerShortcuts:updateItemTable() local item_table = {} for _, item in ipairs(self.folder_shortcuts) do table.insert(item_table, { text = string.format("%s (%s)", item.text, item.folder), folder = item.folder, - friendly_name = item.text, - deletable = true, - editable = true, - callback = function() - UIManager:close(self.fm_bookmark) - - local folder = item.folder - if folder ~= nil and lfs.attributes(folder, "mode") == "directory" then - if select_callback then - select_callback(folder) - else - if self.ui.file_chooser then - self.ui.file_chooser:changeToPath(folder) - else -- called from Reader - self.ui:onClose() - self.ui:showFileManager(folder .. "/") - end - end - end - end, + name = item.text, }) end - table.sort(item_table, function(l, r) return l.text < r.text end) -- try to stay on current page local select_number - - if self.fm_bookmark.page and self.fm_bookmark.perpage and self.fm_bookmark.page > 0 then - select_number = (self.fm_bookmark.page - 1) * self.fm_bookmark.perpage + 1 + if self.shortcuts_menu.page and self.shortcuts_menu.perpage and self.shortcuts_menu.page > 0 then + select_number = (self.shortcuts_menu.page - 1) * self.shortcuts_menu.perpage + 1 end - - self.fm_bookmark:switchItemTable(nil, - item_table, select_number) + self.shortcuts_menu:switchItemTable(nil, item_table, select_number) end -function FileManagerShortcuts:addNewFolder() - local PathChooser = require("ui/widget/pathchooser") - local path_chooser = PathChooser:new{ - select_directory = true, - select_file = false, - path = self.fm_bookmark.curr_path, - onConfirm = function(path) - local add_folder_input - local friendly_name = util.basename(path) or _("my folder") - add_folder_input = InputDialog:new{ - title = _("Enter friendly name"), - input = friendly_name, - description = T(_("Title for selected folder:\n%1"), BD.dirpath(path)), - buttons = { - { - { - text = _("Cancel"), - id = "close", - callback = function() - UIManager:close(add_folder_input) - end, - }, - { - text = _("Add"), - is_enter_default = true, - callback = function() - self:addFolderFromInput(add_folder_input:getInputValue(), path) - UIManager:close(add_folder_input) - end, - }, - } - }, - } - UIManager:show(add_folder_input) - add_folder_input:onShowKeyboard() +function FileManagerShortcuts:_getIndex(folder) + for i, v in ipairs(self.folder_shortcuts) do + if v.folder == folder then + return i end - } - UIManager:show(path_chooser) + end +end + +function FileManagerShortcuts:hasFolderShortcut(folder) + return self:_getIndex(folder) and true or false end -function FileManagerShortcuts:addFolderFromInput(friendly_name, folder) - for __, item in ipairs(self.folder_shortcuts) do - if item.text == friendly_name and item.folder == folder then - UIManager:show(InfoMessage:new{ - text = _("A shortcut to this folder already exists."), - }) - return +function FileManagerShortcuts:onMenuChoice(item) + local folder = item.folder + if lfs.attributes(folder, "mode") ~= "directory" then return end + if self.select_callback then + self.select_callback(folder) + else + if self._manager.ui.file_chooser then + self._manager.ui.file_chooser:changeToPath(folder) + else -- called from Reader + self._manager.ui:onClose() + self._manager.ui:showFileManager(folder .. "/") end end - table.insert(self.folder_shortcuts, { - text = friendly_name, - folder = folder, - }) - self:updateItemTable() end function FileManagerShortcuts:onMenuHold(item) - if item.deletable or item.editable then - local folder_shortcuts_dialog - folder_shortcuts_dialog = ButtonDialog:new{ - buttons = { - { - { - text = _("Paste file"), - enabled = (self._manager.ui.file_chooser and self._manager.ui.clipboard) and true or false, - callback = function() - UIManager:close(folder_shortcuts_dialog) - self._manager.ui:pasteHere(item.folder) - end - }, - { - text = _("Edit"), - enabled = item.editable, - callback = function() - UIManager:close(folder_shortcuts_dialog) - self._manager:editFolderShortcut(item) - end - }, - { - text = _("Delete"), - enabled = item.deletable, - callback = function() - UIManager:close(folder_shortcuts_dialog) - self._manager:deleteFolderShortcut(item) - end - }, - }, - } - } - UIManager:show(folder_shortcuts_dialog) - return true + local dialog + local buttons = { + { + { + text = _("Remove shortcut"), + callback = function() + UIManager:close(dialog) + self._manager:removeShortcut(item.folder) + end + }, + { + text = _("Rename shortcut"), + callback = function() + UIManager:close(dialog) + self._manager:editShortcut(item.folder) + end + }, + }, + } + if self._manager.ui.file_chooser and self._manager.ui.clipboard then + table.insert(buttons, { + { + text = _("Paste to folder"), + callback = function() + UIManager:close(dialog) + self._manager.ui:pasteHere(item.folder) + end + }, + }) end + + dialog = ButtonDialog:new{ + title = item.name .. "\n" .. BD.dirpath(item.folder), + title_align = "center", + buttons = buttons, + } + UIManager:show(dialog) + return true end -function FileManagerShortcuts:editFolderShortcut(item) - local edit_folder_input - edit_folder_input = InputDialog:new { - title = _("Edit friendly name"), - input = item.friendly_name, - description = T(_("Rename title for selected folder:\n%1"), BD.dirpath(item.folder)), - buttons = { +function FileManagerShortcuts:removeShortcut(folder) + local index = self:_getIndex(folder) + table.remove(self.folder_shortcuts, index) + if self.shortcuts_menu then + self.fm_updated = true + self:updateItemTable() + end +end + +function FileManagerShortcuts:editShortcut(folder, post_callback) + local index = self:_getIndex(folder) + local item, name + if index then -- rename + item = self.folder_shortcuts[index] + name = item.text + end + + local input_dialog + input_dialog = InputDialog:new { + title = _("Enter folder shortcut name"), + input = name, + description = BD.dirpath(folder), + buttons = {{ { - { - text = _("Cancel"), - id = "close", - callback = function() - UIManager:close(edit_folder_input) - end, - }, - { - text = _("Apply"), - is_enter_default = true, - callback = function() - self:renameFolderShortcut(item, edit_folder_input:getInputText()) - UIManager:close(edit_folder_input) - end, - }, - } - }, + text = _("Cancel"), + id = "close", + callback = function() + UIManager:close(input_dialog) + end, + }, + { + text = _("Save"), + is_enter_default = true, + callback = function() + local new_name = input_dialog:getInputText() + if new_name == "" or new_name == name then return end + UIManager:close(input_dialog) + if item then + item.text = new_name + else + table.insert(self.folder_shortcuts, { + text = new_name, + folder = folder, + }) + if post_callback then + post_callback() + end + end + if self.shortcuts_menu then + self.fm_updated = true + self:updateItemTable() + end + end, + }, + }}, } - UIManager:show(edit_folder_input) - edit_folder_input:onShowKeyboard() + UIManager:show(input_dialog) + input_dialog:onShowKeyboard() end -function FileManagerShortcuts:renameFolderShortcut(item, new_name) - for _, element in ipairs(self.folder_shortcuts) do - if element.text == item.friendly_name and element.folder == item.folder then - element.text = new_name - end - end - self:updateItemTable() +function FileManagerShortcuts:addShortcut() + local PathChooser = require("ui/widget/pathchooser") + local path_chooser = PathChooser:new{ + select_directory = true, + select_file = false, + path = self.ui.file_chooser and self.ui.file_chooser.path or self.ui:getLastDirFile(), + onConfirm = function(path) + if self:hasFolderShortcut(path) then + UIManager:show(InfoMessage:new{ + text = _("Shortcut already exists."), + }) + else + self:editShortcut(path) + end + end, + } + UIManager:show(path_chooser) end -function FileManagerShortcuts:deleteFolderShortcut(item) - for i = #self.folder_shortcuts, 1, -1 do - local element = self.folder_shortcuts[i] - if element.text == item.friendly_name and element.folder == item.folder then - table.remove(self.folder_shortcuts, i) - end +function FileManagerShortcuts:genShowFolderShortcutsButton(pre_callback) + return { + text = self.title, + callback = function() + pre_callback() + self:onShowFolderShortcutsDialog() + end, + } +end + +function FileManagerShortcuts:genAddRemoveShortcutButton(folder, pre_callback, post_callback) + if self:hasFolderShortcut(folder) then + return { + text = _("Remove from folder shortcuts"), + callback = function() + pre_callback() + self:removeShortcut(folder) + post_callback() + end, + } + else + return { + text = _("Add to folder shortcuts"), + callback = function() + pre_callback() + self:editShortcut(folder, post_callback) + end, + } end - self:updateItemTable() end function FileManagerShortcuts:onSetDimensions(dimen) @@ -208,7 +219,7 @@ end function FileManagerShortcuts:MenuSetRotationModeHandler(rotation) if rotation ~= nil and rotation ~= Screen:getRotationMode() then - UIManager:close(self._manager.fm_bookmark) + UIManager:close(self._manager.shortcuts_menu) if self._manager.ui.view and self._manager.ui.view.onSetRotationMode then self._manager.ui.view:onSetRotationMode(rotation) elseif self._manager.ui.onSetRotationMode then @@ -222,23 +233,33 @@ function FileManagerShortcuts:MenuSetRotationModeHandler(rotation) end function FileManagerShortcuts:onShowFolderShortcutsDialog(select_callback) - self.fm_bookmark = Menu:new{ - title = _("Folder shortcuts"), + self.shortcuts_menu = Menu:new{ + title = self.title, show_parent = self.ui, - no_title = false, - parent = nil, - is_popout = false, + covers_fullscreen = true, is_borderless = true, - curr_path = self.ui.file_chooser and self.ui.file_chooser.path or self.ui:getLastDirFile(), + is_popout = false, + select_callback = select_callback, -- called from PathChooser titlebar left button + title_bar_left_icon = not select_callback and "plus" or nil, + onLeftButtonTap = function() self:addShortcut() end, + onMenuChoice = self.onMenuChoice, onMenuHold = not select_callback and self.onMenuHold or nil, onSetRotationMode = self.MenuSetRotationModeHandler, - title_bar_left_icon = not select_callback and "plus" or nil, - onLeftButtonTap = function() self:addNewFolder() end, _manager = self, } - - self:updateItemTable(select_callback) - UIManager:show(self.fm_bookmark) + self.shortcuts_menu.close_callback = function() + UIManager:close(self.shortcuts_menu) + if self.fm_updated then + if self.ui.file_chooser then + self.ui.file_chooser:refreshPath() + self.ui:updateTitleBarPath() + end + self.fm_updated = nil + end + self.shortcuts_menu = nil + end + self:updateItemTable() + UIManager:show(self.shortcuts_menu) end return FileManagerShortcuts diff --git a/frontend/ui/widget/filechooser.lua b/frontend/ui/widget/filechooser.lua index ca5d77f20..53bbf8d98 100644 --- a/frontend/ui/widget/filechooser.lua +++ b/frontend/ui/widget/filechooser.lua @@ -3,6 +3,7 @@ local datetime = require("datetime") local Device = require("device") local DocSettings = require("docsettings") local DocumentRegistry = require("document/documentregistry") +local FileManagerShortcuts = require("apps/filemanager/filemanagershortcuts") local filemanagerutil = require("apps/filemanager/filemanagerutil") local Menu = require("ui/widget/menu") local UIManager = require("ui/uimanager") @@ -362,6 +363,9 @@ function FileChooser:getMenuItemMandatory(item, collate) if #sub_dirs > 0 then text = T("%1 \u{F114} ", #sub_dirs) .. text end + if FileManagerShortcuts:hasFolderShortcut(item.fullpath) then + text = "☆ " .. text + end end return text end