mirror of
https://github.com/koreader/koreader
synced 2024-11-08 07:10:27 +00:00
4cc620b702
Move as much of the state tracking as possible inside VirtualKeyboard itself. InputDialog unfortunately needs an internal tracking of this state because it needs to know about it *before* the VK is shown, so we have to keep a bit of duplication in there, although we do try much harder to keep everything in sync (at least at function call edges), and to keep the damage contained to, essentially, the toggle button's handler. (Followup to #10803 & #10850)
676 lines
27 KiB
Lua
676 lines
27 KiB
Lua
local Device = require("device")
|
|
|
|
if not Device:isTouchDevice() then
|
|
return { disabled = true }
|
|
end
|
|
|
|
local BD = require("ui/bidi")
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
local DataStorage = require("datastorage")
|
|
local Dispatcher = require("dispatcher")
|
|
local Font = require("ui/font")
|
|
local QRMessage = require("ui/widget/qrmessage")
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local InputDialog = require("ui/widget/inputdialog")
|
|
local LuaSettings = require("luasettings")
|
|
local Notification = require("ui/widget/notification")
|
|
local PathChooser = require("ui/widget/pathchooser")
|
|
local Trapper = require("ui/trapper")
|
|
local UIManager = require("ui/uimanager")
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
|
local ffiutil = require("ffi/util")
|
|
local lfs = require("libs/libkoreader-lfs")
|
|
local logger = require("logger")
|
|
local util = require("util")
|
|
local _ = require("gettext")
|
|
local Screen = require("device").screen
|
|
local T = ffiutil.template
|
|
|
|
local TextEditor = WidgetContainer:extend{
|
|
name = "texteditor",
|
|
settings_file = DataStorage:getSettingsDir() .. "/text_editor.lua",
|
|
settings = nil, -- loaded only when needed
|
|
-- how many to display in menu (10x3 pages minus our 3 default menu items):
|
|
history_menu_size = 27,
|
|
history_keep_size = 60, -- hom many to keep in settings
|
|
normal_font = "x_smallinfofont",
|
|
monospace_font = "infont",
|
|
default_font_size = 20, -- x_smallinfofont default size
|
|
min_file_size_warn = 200000, -- warn/ask when opening files bigger than this
|
|
}
|
|
|
|
function TextEditor:onDispatcherRegisterActions()
|
|
Dispatcher:registerAction("edit_last_edited_file", { category = "none", event = "OpenLastEditedFile", title = _("Text editor: open last file"), general=true, separator = true})
|
|
end
|
|
|
|
function TextEditor:init()
|
|
self:onDispatcherRegisterActions()
|
|
self.ui.menu:registerToMainMenu(self)
|
|
end
|
|
|
|
function TextEditor:loadSettings()
|
|
if self.settings then
|
|
return
|
|
end
|
|
self.settings = LuaSettings:open(self.settings_file)
|
|
-- NOTE: addToHistory assigns a new object
|
|
self.history = self.settings:readSetting("history") or {}
|
|
self.last_view_pos = self.settings:readSetting("last_view_pos") or {}
|
|
self.last_path = self.settings:readSetting("last_path") or ffiutil.realpath(DataStorage:getDataDir())
|
|
self.font_face = self.settings:readSetting("font_face") or self.normal_font
|
|
self.font_size = self.settings:readSetting("font_size") or self.default_font_size
|
|
-- The font settings could be saved in G_reader_setting if we want them
|
|
-- to be re-used by default by InputDialog (on certain conditaions,
|
|
-- when fullscreen or condensed or add_nav_bar...)
|
|
--
|
|
-- Allow users to set their prefered font manually in text_editor.lua
|
|
-- (sadly, not via TextEditor itself, as they would be overriden on close)
|
|
if self.settings:has("normal_font") then
|
|
self.normal_font = self.settings:readSetting("normal_font")
|
|
end
|
|
if self.settings:has("monospace_font") then
|
|
self.monospace_font = self.settings:readSetting("monospace_font")
|
|
end
|
|
self.auto_para_direction = self.settings:nilOrTrue("auto_para_direction")
|
|
self.force_ltr_para_direction = self.settings:isTrue("force_ltr_para_direction")
|
|
self.qr_code_export = self.settings:nilOrTrue("qr_code_export")
|
|
self.show_keyboard_on_start = self.settings:nilOrTrue("show_keyboard_on_start")
|
|
end
|
|
|
|
function TextEditor:onFlushSettings()
|
|
if self.settings then
|
|
self.settings:saveSetting("history", self.history)
|
|
self.settings:saveSetting("last_view_pos", self.last_view_pos)
|
|
self.settings:saveSetting("last_path", self.last_path)
|
|
self.settings:saveSetting("font_face", self.font_face)
|
|
self.settings:saveSetting("font_size", self.font_size)
|
|
self.settings:saveSetting("auto_para_direction", self.auto_para_direction)
|
|
self.settings:saveSetting("force_ltr_para_direction", self.force_ltr_para_direction)
|
|
self.settings:saveSetting("qr_code_export", self.qr_code_export)
|
|
self.settings:saveSetting("show_keyboard_on_start", self.show_keyboard_on_start)
|
|
self.settings:flush()
|
|
end
|
|
end
|
|
|
|
function TextEditor:addToMainMenu(menu_items)
|
|
menu_items.text_editor = {
|
|
text = _("Text editor"),
|
|
sub_item_table_func = function()
|
|
return self:getSubMenuItems()
|
|
end,
|
|
}
|
|
end
|
|
|
|
function TextEditor:getSubMenuItems()
|
|
self:loadSettings()
|
|
self.whenDoneFunc = nil -- discard reference to previous TouchMenu instance
|
|
local sub_item_table
|
|
sub_item_table = {
|
|
{
|
|
text = _("Settings"),
|
|
sub_item_table = {
|
|
{
|
|
text_func = function()
|
|
return T(_("Text font size: %1"), self.font_size)
|
|
end,
|
|
keep_menu_open = true,
|
|
callback = function(touchmenu_instance)
|
|
local SpinWidget = require("ui/widget/spinwidget")
|
|
local font_size = self.font_size
|
|
UIManager:show(SpinWidget:new{
|
|
value = font_size,
|
|
value_min = 8,
|
|
value_max = 26,
|
|
default_value = self.default_font_size,
|
|
title_text = _("Text font size"),
|
|
callback = function(spin)
|
|
self.font_size = spin.value
|
|
touchmenu_instance:updateItems()
|
|
end,
|
|
})
|
|
end,
|
|
},
|
|
{
|
|
text = _("Use monospace font"),
|
|
checked_func = function()
|
|
return self.font_face == self.monospace_font
|
|
end,
|
|
callback = function()
|
|
if self.font_face == self.monospace_font then
|
|
self.font_face = self.normal_font
|
|
else
|
|
self.font_face = self.monospace_font
|
|
end
|
|
end,
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("Auto paragraph direction"),
|
|
help_text = _([[
|
|
Detect the direction of each paragraph in the text: align to the right paragraphs in languages such as Arabic and Hebrew…, while keeping other paragraphs aligned to the left.
|
|
If disabled, paragraphs align according to KOReader's language default direction.]]),
|
|
checked_func = function()
|
|
return self.auto_para_direction
|
|
end,
|
|
callback = function()
|
|
self.auto_para_direction = not self.auto_para_direction
|
|
end,
|
|
},
|
|
{
|
|
text = _("Force paragraph direction LTR"),
|
|
help_text = _([[
|
|
Force all text to be displayed Left-To-Right (LTR) and aligned to the left.
|
|
Enable this if you are mostly editing code, HTML, CSS…]]),
|
|
enabled_func = BD.rtlUIText, -- only useful for RTL users editing code
|
|
checked_func = function()
|
|
return BD.rtlUIText() and self.force_ltr_para_direction
|
|
end,
|
|
callback = function()
|
|
self.force_ltr_para_direction = not self.force_ltr_para_direction
|
|
end,
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("Show keyboard on start"),
|
|
checked_func = function()
|
|
return self.show_keyboard_on_start
|
|
end,
|
|
callback = function()
|
|
self.show_keyboard_on_start = not self.show_keyboard_on_start
|
|
end,
|
|
},
|
|
{
|
|
text = _("Enable QR code export"),
|
|
help_text = _([[
|
|
Export text to QR code, that can be scanned, for example, by a phone.]]),
|
|
checked_func = function()
|
|
return self.qr_code_export
|
|
end,
|
|
callback = function()
|
|
self.qr_code_export = not self.qr_code_export
|
|
end,
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("Clean text editor history"),
|
|
enabled_func = function()
|
|
return #self.history > 0
|
|
end,
|
|
keep_menu_open = true,
|
|
callback = function(touchmenu_instance)
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Clean text editor history?"),
|
|
ok_text = _("Clean"),
|
|
ok_callback = function()
|
|
self.history = {}
|
|
self.last_view_pos = {}
|
|
-- remove history items from the parent menu
|
|
for j = #sub_item_table, 1, -1 do
|
|
if sub_item_table[j]._texteditor_id then
|
|
table.remove(sub_item_table)
|
|
end
|
|
end
|
|
touchmenu_instance:updateItems()
|
|
end,
|
|
})
|
|
end,
|
|
},
|
|
},
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("New file"),
|
|
keep_menu_open = true,
|
|
callback = function(touchmenu_instance)
|
|
self:setupWhenDoneFunc(touchmenu_instance)
|
|
self:newFile()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Open file"),
|
|
keep_menu_open = true,
|
|
callback = function(touchmenu_instance)
|
|
self:setupWhenDoneFunc(touchmenu_instance)
|
|
self:chooseFile()
|
|
end,
|
|
separator = true,
|
|
},
|
|
}
|
|
for i=1, math.min(#self.history, self.history_menu_size) do
|
|
local file_path = self.history[i]
|
|
local directory, filename = util.splitFilePathName(file_path) -- luacheck: no unused
|
|
table.insert(sub_item_table, {
|
|
text = T("\u{f016} %1", BD.filename(filename)), -- file symbol
|
|
keep_menu_open = true,
|
|
callback = function(touchmenu_instance)
|
|
self:setupWhenDoneFunc(touchmenu_instance)
|
|
self:checkEditFile(file_path, true)
|
|
end,
|
|
_texteditor_id = file_path, -- for removal from menu itself
|
|
hold_callback = function(touchmenu_instance)
|
|
-- Show full path and some info, and propose to remove from history
|
|
local text
|
|
local attr = lfs.attributes(file_path)
|
|
if attr then
|
|
local filesize = util.getFormattedSize(attr.size)
|
|
local lastmod = os.date("%Y-%m-%d %H:%M", attr.modification)
|
|
text = T(_("File path:\n%1\n\nFile size: %2 bytes\nLast modified: %3\n\nRemove this file from text editor history?"),
|
|
BD.filepath(file_path), filesize, lastmod)
|
|
else
|
|
text = T(_("File path:\n%1\n\nThis file does not exist anymore.\n\nRemove it from text editor history?"),
|
|
BD.filepath(file_path))
|
|
end
|
|
UIManager:show(ConfirmBox:new{
|
|
text = text,
|
|
ok_text = _("Remove"),
|
|
ok_callback = function()
|
|
self:removeFromHistory(file_path)
|
|
-- Also remove from menu itself
|
|
for j=1, #sub_item_table do
|
|
if sub_item_table[j]._texteditor_id == file_path then
|
|
table.remove(sub_item_table, j)
|
|
break
|
|
end
|
|
end
|
|
touchmenu_instance:updateItems()
|
|
end,
|
|
})
|
|
end,
|
|
})
|
|
end
|
|
return sub_item_table
|
|
end
|
|
|
|
function TextEditor:setupWhenDoneFunc(touchmenu_instance)
|
|
-- This will keep a reference to the TouchMenu instance, that may not
|
|
-- get released if file opening is aborted while in the file selection
|
|
-- widgets and dialogs (quite complicated to call a resetWhenDoneFunc()
|
|
-- in every abort case). But :getSubMenuItems() will release it when
|
|
-- the TextEditor menu is opened again.
|
|
self.whenDoneFunc = function()
|
|
touchmenu_instance.item_table = self:getSubMenuItems()
|
|
touchmenu_instance.page = 1
|
|
touchmenu_instance:updateItems()
|
|
end
|
|
end
|
|
|
|
function TextEditor:execWhenDoneFunc()
|
|
if self.whenDoneFunc then
|
|
self.whenDoneFunc()
|
|
self.whenDoneFunc = nil
|
|
end
|
|
end
|
|
|
|
function TextEditor:removeFromHistory(file_path)
|
|
for i = #self.history, 1, -1 do
|
|
if self.history[i] == file_path then
|
|
table.remove(self.history, i)
|
|
end
|
|
end
|
|
self.last_view_pos[file_path] = nil
|
|
end
|
|
|
|
function TextEditor:addToHistory(file_path)
|
|
local new_history = {}
|
|
table.insert(new_history, file_path)
|
|
-- Trim history and cleanup duplicates
|
|
local seen = {}
|
|
seen[file_path] = true
|
|
while #self.history > 0 and #new_history < self.history_keep_size do
|
|
local item = table.remove(self.history, 1)
|
|
if not seen[item] then
|
|
table.insert(new_history, item)
|
|
seen[item] = true
|
|
end
|
|
end
|
|
self.history = new_history
|
|
end
|
|
|
|
function TextEditor:newFile()
|
|
self:loadSettings()
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _([[To start editing a new file, you will have to:
|
|
|
|
- First choose a folder
|
|
- Then enter a name for the new file
|
|
- And start editing it
|
|
|
|
Do you want to proceed?]]),
|
|
ok_text = _("Yes"),
|
|
cancel_text = _("No"),
|
|
ok_callback = function()
|
|
local path_chooser = PathChooser:new{
|
|
select_file = false,
|
|
path = self.last_path,
|
|
onConfirm = function(dir_path)
|
|
local file_input
|
|
file_input = InputDialog:new{
|
|
title = _("Enter filename"),
|
|
input = dir_path == "/" and "/" or dir_path .. "/",
|
|
buttons = {{
|
|
{
|
|
text = _("Cancel"),
|
|
id = "close",
|
|
callback = function()
|
|
UIManager:close(file_input)
|
|
end,
|
|
},
|
|
{
|
|
text = _("Edit"),
|
|
callback = function()
|
|
local file_path = file_input:getInputText()
|
|
UIManager:close(file_input)
|
|
-- Remember last_path
|
|
self.last_path = file_path:match("(.*)/")
|
|
if self.last_path == "" then self.last_path = "/" end
|
|
self:checkEditFile(file_path, false, true)
|
|
end,
|
|
},
|
|
}},
|
|
}
|
|
UIManager:show(file_input)
|
|
file_input:onShowKeyboard()
|
|
end,
|
|
}
|
|
UIManager:show(path_chooser)
|
|
end,
|
|
})
|
|
end
|
|
|
|
function TextEditor:chooseFile()
|
|
self:loadSettings()
|
|
local path_chooser = PathChooser:new{
|
|
select_directory = false,
|
|
path = self.last_path,
|
|
onConfirm = function(file_path)
|
|
-- Remember last_path only when we select a file from it
|
|
self.last_path = file_path:match("(.*)/")
|
|
if self.last_path == "" then self.last_path = "/" end
|
|
self:checkEditFile(file_path)
|
|
end
|
|
}
|
|
UIManager:show(path_chooser)
|
|
end
|
|
|
|
function TextEditor:checkEditFile(file_path, from_history, possibly_new_file)
|
|
self:loadSettings()
|
|
local attr = lfs.attributes(file_path)
|
|
if not possibly_new_file and not attr then
|
|
UIManager:show(ConfirmBox:new{
|
|
text = T(_("This file does not exist anymore:\n\n%1\n\nDo you want to create it and start editing it?"), BD.filepath(file_path)),
|
|
ok_text = _("Create"),
|
|
ok_callback = function()
|
|
-- go again thru there with possibly_new_file=true
|
|
self:checkEditFile(file_path, from_history, true)
|
|
end,
|
|
})
|
|
return
|
|
end
|
|
if attr then
|
|
-- File exists: get its real path with symlink and ../ resolved
|
|
file_path = ffiutil.realpath(file_path)
|
|
attr = lfs.attributes(file_path)
|
|
end
|
|
if attr then -- File exists
|
|
if attr.mode ~= "file" then
|
|
UIManager:show(InfoMessage:new{
|
|
text = T(_("This file is not a regular file:\n\n%1"), BD.filepath(file_path))
|
|
})
|
|
return
|
|
end
|
|
-- Check if file is writable ("r+b" checks that, and does not
|
|
-- update the last mod timestamp, unlike "wb")
|
|
-- No need to warn if readonly, the user will know it when we open
|
|
-- without keyboard and the Save button says "Read only".
|
|
local readonly = true
|
|
local file = io.open(file_path, 'r+b')
|
|
if file then
|
|
file:close()
|
|
readonly = false
|
|
end
|
|
-- Don't check size if coming from history: user had already confirmed it
|
|
if not from_history and attr.size > self.min_file_size_warn then
|
|
UIManager:show(ConfirmBox:new{
|
|
text = T(_("This file is %2:\n\n%1\n\nAre you sure you want to open it?\n\nOpening big files may take some time."),
|
|
BD.filepath(file_path), util.getFriendlySize(attr.size)),
|
|
ok_text = _("Open"),
|
|
ok_callback = function()
|
|
self:editFile(file_path, readonly)
|
|
end,
|
|
})
|
|
else
|
|
self:editFile(file_path, readonly)
|
|
end
|
|
else -- File does not exist
|
|
-- Try to create it just to check if writting to it later is possible
|
|
local file, err = io.open(file_path, "wb")
|
|
if file then
|
|
-- Clean it, we'll create it again on Save, and allow closing
|
|
-- without saving in case the user has changed his mind.
|
|
file:close()
|
|
os.remove(file_path)
|
|
self:editFile(file_path)
|
|
else
|
|
UIManager:show(InfoMessage:new{
|
|
text = T(_("This file can not be created:\n\n%1\n\nReason: %2"), BD.filepath(file_path), err)
|
|
})
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function TextEditor:readFileContent(file_path)
|
|
local file = io.open(file_path, "rb")
|
|
if not file then
|
|
-- We checked file existence before, so assume it's
|
|
-- because it's a new file
|
|
return ""
|
|
end
|
|
local file_content = file:read("*all")
|
|
file:close()
|
|
return file_content
|
|
end
|
|
|
|
function TextEditor:saveFileContent(file_path, content)
|
|
local file, err = io.open(file_path, "wb")
|
|
if file then
|
|
file:write(content)
|
|
file:close()
|
|
logger.info("TextEditor: saved file", file_path)
|
|
return true
|
|
end
|
|
logger.info("TextEditor: failed saving file", file_path, ":", err)
|
|
return false, err
|
|
end
|
|
|
|
function TextEditor:deleteFile(file_path)
|
|
local ok, err = os.remove(file_path)
|
|
if ok then
|
|
logger.info("TextEditor: deleted file", file_path)
|
|
return true
|
|
end
|
|
logger.info("TextEditor: failed deleting file", file_path, ":", err)
|
|
return false, err
|
|
end
|
|
|
|
function TextEditor:editFile(file_path, readonly)
|
|
self:addToHistory(file_path)
|
|
local directory, filename = util.splitFilePathName(file_path) -- luacheck: no unused
|
|
local filename_without_suffix, filetype = util.splitFileNameSuffix(filename) -- luacheck: no unused
|
|
local is_lua = filetype:lower() == "lua"
|
|
local input
|
|
local para_direction_rtl = nil -- use UI language direction
|
|
if self.force_ltr_para_direction then
|
|
para_direction_rtl = false -- force LTR
|
|
end
|
|
local buttons_first_row = {} -- First button on first row, that will be filled with Reset|Save|Close
|
|
if is_lua then
|
|
table.insert(buttons_first_row, {
|
|
text = _("Lua check"),
|
|
callback = function()
|
|
local parse_error = util.checkLuaSyntax(input:getInputText())
|
|
if parse_error then
|
|
UIManager:show(InfoMessage:new{
|
|
text = T(_("Lua syntax check failed:\n\n%1"), parse_error)
|
|
})
|
|
else
|
|
UIManager:show(Notification:new{
|
|
text = T(_("Lua syntax OK")),
|
|
})
|
|
end
|
|
end,
|
|
})
|
|
end
|
|
if self.qr_code_export then
|
|
table.insert(buttons_first_row, {
|
|
text = _("QR"),
|
|
callback = function()
|
|
UIManager:show(QRMessage:new{
|
|
text = input:getInputText(),
|
|
height = Screen:getHeight(),
|
|
width = Screen:getWidth()
|
|
})
|
|
end,
|
|
})
|
|
end
|
|
input = InputDialog:new{
|
|
title = filename,
|
|
input = self:readFileContent(file_path),
|
|
input_face = Font:getFace(self.font_face, self.font_size),
|
|
para_direction_rtl = para_direction_rtl,
|
|
auto_para_direction = self.auto_para_direction,
|
|
fullscreen = true,
|
|
condensed = true,
|
|
allow_newline = true,
|
|
cursor_at_end = false,
|
|
readonly = readonly,
|
|
add_nav_bar = true,
|
|
keyboard_visible = self.show_keyboard_on_start, -- InputDialog will enforce false if readonly
|
|
scroll_by_pan = true,
|
|
buttons = {buttons_first_row},
|
|
-- Store/retrieve view and cursor position callback
|
|
view_pos_callback = function(top_line_num, charpos)
|
|
-- This same callback is called with no arguments on init to retrieve the stored initial position,
|
|
-- and with arguments to store the final position on close.
|
|
if top_line_num and charpos then
|
|
self.last_view_pos[file_path] = {top_line_num, charpos}
|
|
else
|
|
local prev_pos = self.last_view_pos[file_path]
|
|
if type(prev_pos) == "table" and prev_pos[1] and prev_pos[2] then
|
|
return prev_pos[1], prev_pos[2]
|
|
end
|
|
return nil, nil -- no previous position known
|
|
end
|
|
end,
|
|
-- File restoring callback
|
|
reset_callback = function(content) -- Will add a Reset button
|
|
return self:readFileContent(file_path), _("Text reset to last saved content")
|
|
end,
|
|
-- Close callback
|
|
close_callback = function()
|
|
self:execWhenDoneFunc()
|
|
end,
|
|
-- File saving callback
|
|
save_callback = function(content, closing) -- Will add Save/Close buttons
|
|
if readonly then
|
|
-- We shouldn't be called if read-only, but just in case
|
|
return false, _("File is read only")
|
|
end
|
|
if content and #content > 0 then
|
|
if not is_lua then
|
|
local ok, err = self:saveFileContent(file_path, content)
|
|
if ok then
|
|
return true, _("File saved")
|
|
else
|
|
return false, T(_("Failed saving file: %1"), err)
|
|
end
|
|
end
|
|
local parse_error = util.checkLuaSyntax(content)
|
|
if not parse_error then
|
|
local ok, err = self:saveFileContent(file_path, content)
|
|
if ok then
|
|
return true, _("Lua syntax OK, file saved")
|
|
else
|
|
return false, T(_("Failed saving file: %1"), err)
|
|
end
|
|
end
|
|
local save_anyway = Trapper:confirm(T(_([[
|
|
Lua syntax check failed:
|
|
|
|
%1
|
|
|
|
KOReader may crash if this is saved.
|
|
Do you really want to save to this file?
|
|
|
|
%2]]), parse_error, BD.filepath(file_path)), _("Do not save"), _("Save anyway"))
|
|
-- we'll get the safer "Do not save" on tap outside
|
|
if save_anyway then
|
|
local ok, err = self:saveFileContent(file_path, content)
|
|
if ok then
|
|
return true, _("File saved")
|
|
else
|
|
return false, T(_("Failed saving file: %1"), err)
|
|
end
|
|
else
|
|
return false, false -- no need for more InfoMessage
|
|
end
|
|
else -- If content is empty, propose to delete the file
|
|
local delete_file = Trapper:confirm(T(_([[
|
|
Text content is empty.
|
|
Do you want to keep this file as empty, or do you prefer to delete it?
|
|
|
|
%1]]), BD.filepath(file_path)), _("Keep empty file"), _("Delete file"))
|
|
-- we'll get the safer "Keep empty file" on tap outside
|
|
if delete_file then
|
|
local ok, err = self:deleteFile(file_path)
|
|
if ok then
|
|
return true, _("File deleted")
|
|
else
|
|
return false, T(_("Failed deleting file: %1"), err)
|
|
end
|
|
else
|
|
local ok, err = self:saveFileContent(file_path, content)
|
|
if ok then
|
|
return true, _("File saved")
|
|
else
|
|
return false, T(_("Failed saving file: %1"), err)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
}
|
|
UIManager:show(input)
|
|
if self.show_keyboard_on_start and not readonly then
|
|
input:onShowKeyboard()
|
|
end
|
|
-- Note about readonly:
|
|
-- We might have liked to still show keyboard even if readonly, just
|
|
-- to use the arrow keys for line by line scrolling with cursor.
|
|
-- But it's easier to just let InputDialog and InputText do their
|
|
-- own readonly prevention (and on devices where we run as root, we
|
|
-- will hardly ever be readonly).
|
|
end
|
|
|
|
-- reopen last edited file. Invokeable with gesture:
|
|
function TextEditor:onOpenLastEditedFile()
|
|
self:loadSettings()
|
|
if #self.history > 0 then
|
|
local file_path = self.history[1]
|
|
self:checkEditFile(file_path, true)
|
|
else
|
|
self:chooseFile()
|
|
end
|
|
end
|
|
|
|
-- quickly open and edit a file
|
|
-- calls the done_callback function on close
|
|
function TextEditor:quickEditFile(file_path, done_callback, possible_new_file)
|
|
if done_callback then
|
|
self.whenDoneFunc = done_callback
|
|
end
|
|
self:checkEditFile(file_path, possible_new_file or false)
|
|
end
|
|
|
|
return TextEditor
|