2020-01-04 00:18:51 +00:00
|
|
|
local BD = require("ui/bidi")
|
2022-07-27 16:02:37 +00:00
|
|
|
local ButtonDialog = require("ui/widget/buttondialog")
|
2022-01-21 17:28:04 +00:00
|
|
|
local Device = require("device")
|
2014-09-10 04:25:08 +00:00
|
|
|
local FileChooser = require("ui/widget/filechooser")
|
|
|
|
local UIManager = require("ui/uimanager")
|
2018-08-06 18:59:01 +00:00
|
|
|
local ffiutil = require("ffi/util")
|
|
|
|
local lfs = require("libs/libkoreader-lfs")
|
|
|
|
local util = require("util")
|
2014-09-10 04:25:08 +00:00
|
|
|
local _ = require("gettext")
|
2024-01-26 21:03:28 +00:00
|
|
|
local N_ = _.ngettext
|
2018-08-06 18:59:01 +00:00
|
|
|
local T = ffiutil.template
|
2014-09-10 04:25:08 +00:00
|
|
|
|
|
|
|
local PathChooser = FileChooser:extend{
|
2018-08-06 18:59:01 +00:00
|
|
|
title = true, -- or a string
|
|
|
|
-- if let to true, a generic title will be set in init()
|
2014-09-10 04:25:08 +00:00
|
|
|
no_title = false,
|
|
|
|
is_popout = false,
|
Text input fixes and enhancements (#4084)
InputText, ScrollTextWidget, TextBoxWidget:
- proper line scrolling when moving cursor or inserting/deleting text
to behave like most text editors do
- fix cursor navigation, optimize refreshes when moving only the cursor,
don't recreate the textwidget when moving cursor up/down
- optimize refresh areas, stick to "ui" to avoid a "partial" black
flash every 6 appended or deleted chars
InputText:
- fix issue when toggling Show password multiple times
- new option: InputText.cursor_at_end (default: true)
- if no InputText.height provided, measure the text widget height
that we would start with, and use a ScrollTextWidget with that
fixed height, so widget does not overflow container if we extend
the text and increase the number of lines
- as we are using "ui" refreshes while text editing, allows refreshing
the InputText with a diagonal swipe on it (actually, refresh the
whole screen, which allows refreshing the keyboard too if needed)
ScrollTextWidget:
- properly align scrollbar with its TextBoxWidget
TextBoxWidget:
- some cleanup (added new properties to avoid many method calls), added
proxy methods for upper widgets to get them
- reordered/renamed/refactored the *CharPos* methods for easier reading
(sorry for the diff that won't help reviewing, but that was needed)
InputDialog:
- new options:
allow_newline = false, -- allow entering new lines
cursor_at_end = true, -- starts with cursor at end of text, ready to append
fullscreen = false, -- adjust to full screen minus keyboard
condensed = false, -- true will prevent adding air and balance between elements
add_scroll_buttons = false, -- add scroll Up/Down buttons to first row of buttons
add_nav_bar = false, -- append a row of page navigation buttons
- find the most adequate text height, when none provided or fullscreen, to
not overflow screen (and not be stuck with Cancel/Save buttons hidden)
- had to disable the use of a MovableContainer (many issues like becoming
transparent when a PathChooser comes in front, Hold to paste from
clipboard, moving the InputDialog under the keyboard and getting stuck...)
GestureRange: fix possible crash (when event processed after widget
destruction ?)
LoginDialog: fix some ui stack increase and possible crash when switching
focus many times.
2018-07-19 06:30:40 +00:00
|
|
|
covers_fullscreen = true, -- set it to false if you set is_popout = true
|
2014-09-10 04:25:08 +00:00
|
|
|
is_borderless = true,
|
2018-08-06 18:59:01 +00:00
|
|
|
select_directory = true, -- allow selecting directories
|
|
|
|
select_file = true, -- allow selecting files
|
2022-07-27 16:02:37 +00:00
|
|
|
show_files = true, -- show files, even if select_file=false
|
2018-08-06 18:59:01 +00:00
|
|
|
-- (directories are always shown, to allow navigation)
|
2022-07-27 16:02:37 +00:00
|
|
|
detailed_file_info = true, -- show size and last mod time in Select message (if select_file=true only)
|
2014-09-10 04:25:08 +00:00
|
|
|
}
|
|
|
|
|
2018-08-06 18:59:01 +00:00
|
|
|
function PathChooser:init()
|
|
|
|
if self.title == true then -- default title depending on options
|
|
|
|
if self.select_directory and not self.select_file then
|
2021-08-24 20:19:07 +00:00
|
|
|
self.title = _("Long-press to choose a folder")
|
2018-08-06 18:59:01 +00:00
|
|
|
elseif not self.select_directory and self.select_file then
|
2021-08-24 20:19:07 +00:00
|
|
|
self.title = _("Long-press to choose a file")
|
2018-08-06 18:59:01 +00:00
|
|
|
else
|
2021-08-24 20:19:07 +00:00
|
|
|
self.title = _("Long-press to choose")
|
2018-08-06 18:59:01 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
if not self.show_files then
|
|
|
|
self.file_filter = function() return false end -- filter out regular files
|
|
|
|
end
|
2023-10-12 05:58:52 +00:00
|
|
|
if self.file_filter then
|
|
|
|
self.show_unsupported = false -- honour file_filter
|
|
|
|
end
|
2018-08-06 18:59:01 +00:00
|
|
|
if self.select_directory then
|
2021-08-24 20:19:07 +00:00
|
|
|
-- Let FileChooser display "Long-press to choose current folder"
|
2018-08-06 18:59:01 +00:00
|
|
|
self.show_current_dir_for_hold = true
|
|
|
|
end
|
2022-01-11 12:47:06 +00:00
|
|
|
self.title_bar_left_icon = "home"
|
|
|
|
self.onLeftButtonTap = function()
|
|
|
|
self:goHome()
|
|
|
|
end
|
2022-02-07 16:11:08 +00:00
|
|
|
self.onLeftButtonHold = function()
|
2022-07-27 16:02:37 +00:00
|
|
|
self:showPlusMenu()
|
2022-02-07 16:11:08 +00:00
|
|
|
end
|
2018-08-06 18:59:01 +00:00
|
|
|
FileChooser.init(self)
|
|
|
|
end
|
|
|
|
|
2014-09-10 04:25:08 +00:00
|
|
|
function PathChooser:onMenuSelect(item)
|
2018-08-06 18:59:01 +00:00
|
|
|
local path = item.path
|
|
|
|
if path:sub(-2, -1) == "/." then -- with show_current_dir_for_hold
|
2022-01-21 17:28:04 +00:00
|
|
|
if not Device:isTouchDevice() and self.select_directory then -- let non-touch device can select the folder
|
|
|
|
return self:onMenuHold(item)
|
|
|
|
end
|
2018-08-06 18:59:01 +00:00
|
|
|
-- Don't navigate to same directory
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
path = ffiutil.realpath(path)
|
|
|
|
if not path then
|
|
|
|
-- If starting in a no-more existing directory, allow
|
|
|
|
-- not getting stuck in it
|
|
|
|
self:changeToPath("/")
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
local attr = lfs.attributes(path)
|
|
|
|
if not attr then
|
|
|
|
-- Same as above
|
|
|
|
self:changeToPath("/")
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if attr.mode ~= "directory" then
|
2022-01-21 17:28:04 +00:00
|
|
|
if not Device:isTouchDevice() and self.select_file then -- let non-touch device can select the file
|
|
|
|
return self:onMenuHold(item)
|
|
|
|
end
|
2018-08-06 18:59:01 +00:00
|
|
|
-- Do nothing if Tap on other than directories
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
-- Let this method check permissions and if we can list
|
|
|
|
-- this directory: we should get at least one item: ".."
|
|
|
|
local sub_table = self:genItemTableFromPath(path)
|
|
|
|
if #sub_table > 0 then
|
|
|
|
self:changeToPath(path)
|
2014-09-10 04:25:08 +00:00
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function PathChooser:onMenuHold(item)
|
2018-08-06 18:59:01 +00:00
|
|
|
local path = item.path
|
|
|
|
if path:sub(-2, -1) == "/." then -- with show_current_dir_for_hold
|
|
|
|
path = path:sub(1, -3)
|
|
|
|
end
|
|
|
|
path = ffiutil.realpath(path)
|
|
|
|
if not path then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
local attr = lfs.attributes(path)
|
|
|
|
if not attr then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if attr.mode == "file" and not self.select_file then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if attr.mode == "directory" and not self.select_directory then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
local title
|
|
|
|
if attr.mode == "file" then
|
2024-01-26 21:03:28 +00:00
|
|
|
title = _("Choose this file?") .. "\n\n" .. BD.filepath(path) .. "\n"
|
2018-08-06 18:59:01 +00:00
|
|
|
if self.detailed_file_info then
|
|
|
|
local filesize = util.getFormattedSize(attr.size)
|
|
|
|
local lastmod = os.date("%Y-%m-%d %H:%M", attr.modification)
|
2024-01-26 21:03:28 +00:00
|
|
|
title = title .. "\n" .. T(N_("File size: 1 byte", "File size: %1 bytes", attr.size), filesize) ..
|
|
|
|
"\n" .. T(_("Last modified: %1"), lastmod) .. "\n"
|
2018-08-06 18:59:01 +00:00
|
|
|
end
|
|
|
|
elseif attr.mode == "directory" then
|
2024-01-26 21:03:28 +00:00
|
|
|
title = _("Choose this folder?") .. "\n\n" .. BD.dirpath(path) .. "\n"
|
2018-08-06 18:59:01 +00:00
|
|
|
else -- just in case we get something else
|
2024-01-26 21:03:28 +00:00
|
|
|
title = _("Choose this path?") .. "\n\n" .. BD.path(path) .. "\n"
|
2018-08-06 18:59:01 +00:00
|
|
|
end
|
2014-09-10 04:25:08 +00:00
|
|
|
local onConfirm = self.onConfirm
|
2023-10-12 05:58:52 +00:00
|
|
|
self.button_dialog = ButtonDialog:new{
|
2018-08-06 18:59:01 +00:00
|
|
|
title = title,
|
2014-09-10 04:25:08 +00:00
|
|
|
buttons = {
|
|
|
|
{
|
|
|
|
{
|
2018-08-06 18:59:01 +00:00
|
|
|
text = _("Cancel"),
|
2014-09-10 04:25:08 +00:00
|
|
|
callback = function()
|
|
|
|
UIManager:close(self.button_dialog)
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
{
|
2021-08-24 20:19:07 +00:00
|
|
|
text = _("Choose"),
|
2014-09-10 04:25:08 +00:00
|
|
|
callback = function()
|
2018-08-06 18:59:01 +00:00
|
|
|
if onConfirm then
|
|
|
|
onConfirm(path)
|
|
|
|
end
|
2014-09-10 04:25:08 +00:00
|
|
|
UIManager:close(self.button_dialog)
|
|
|
|
UIManager:close(self)
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
UIManager:show(self.button_dialog)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2022-07-27 16:02:37 +00:00
|
|
|
function PathChooser:showPlusMenu()
|
|
|
|
local button_dialog
|
|
|
|
button_dialog = ButtonDialog:new{
|
|
|
|
buttons = {
|
|
|
|
{
|
|
|
|
{
|
|
|
|
text = _("Folder shortcuts"),
|
|
|
|
callback = function()
|
|
|
|
UIManager:close(button_dialog)
|
2024-01-26 21:03:28 +00:00
|
|
|
local FileManagerShortcuts = require("apps/filemanager/filemanagershortcuts")
|
|
|
|
local select_callback = function(path)
|
|
|
|
self:changeToPath(path)
|
|
|
|
end
|
|
|
|
FileManagerShortcuts:onShowFolderShortcutsDialog(select_callback)
|
2022-07-27 16:02:37 +00:00
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
text = _("New folder"),
|
|
|
|
callback = function()
|
|
|
|
UIManager:close(button_dialog)
|
|
|
|
local FileManager = require("apps/filemanager/filemanager")
|
|
|
|
FileManager.file_chooser = self
|
|
|
|
FileManager:createFolder()
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
UIManager:show(button_dialog)
|
|
|
|
end
|
|
|
|
|
2014-09-10 04:25:08 +00:00
|
|
|
return PathChooser
|