Files
koreader/frontend/apps/filemanager/filemanagersetdefaults.lua
onde2rock e502bf04d3 [feat, UX] Support the virtualKeyboard on non touch-device (#3796)
* [VirtualKeyboard] Add support for keynaviguation

Also rename the variable "layout" to "keyboard_layout" because conflict
with the layout from the focusmanager

* Make the goto dialog compatible with key naviguation

My solution is to change the order of the widget. The last one will the
virtualkeybard so it catch all the keybinding, and below it, make the
dialog "is_always_active = true" so it can receive touch event.

* Correctly show the virtual keyboard on dpad devices

* change the order to call the virtualKeyboard so it end up on top

* Handle the multi input dialog

* Support reopening the virtualKeyboard by the Press key

* add check focusmanager

* Fix https://github.com/koreader/koreader/issues/3797

* MultiInputDialog : Now work on non touch-device

* Set the virtualkeyboard to be a modal widget

* Fix the layout in multiinputwidget

* Fix for the various combination of
hasKeys,hasDpad,isTouchDevice

* [Focusmanager] Better handling of malformed layout
2018-03-30 12:46:36 +02:00

354 lines
13 KiB
Lua

local CenterContainer = require("ui/widget/container/centercontainer")
local ConfirmBox = require("ui/widget/confirmbox")
local DataStorage = require("datastorage")
local Font = require("ui/font")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local Menu = require("ui/widget/menu")
local MultiInputDialog = require("ui/widget/multiinputdialog")
local UIManager = require("ui/uimanager")
local dump = require("dump")
local isAndroid, android = pcall(require, "android")
local util = require("ffi/util")
local _ = require("gettext")
local Screen = require("device").screen
local function getDefaultsPath()
local defaults_path = DataStorage:getDataDir() .. "/defaults.lua"
if isAndroid then
defaults_path = android.dir .. "/defaults.lua"
end
return defaults_path
end
local defaults_path = getDefaultsPath()
local persistent_defaults_path = DataStorage:getDataDir() .. "/defaults.persistent.lua"
local SetDefaults = InputContainer:new{
defaults_name = {},
defaults_value = {},
results = {},
defaults_menu = {},
initialized = false,
changed = {},
settings_changed = false,
}
function SetDefaults:ConfirmEdit()
if not SetDefaults.EditConfirmed then
UIManager:show(ConfirmBox:new{
text = _("Some changes will not work until the next restart. Be careful; the wrong settings might crash KOReader!\nAre you sure you want to continue?"),
ok_callback = function()
self.EditConfirmed = true
self:init()
end,
})
else
self:init()
end
end
function SetDefaults:init()
self.results = {}
if not self.initialized then
local defaults = {}
local load_defaults = loadfile(defaults_path)
setfenv(load_defaults, defaults)
load_defaults()
local file = io.open(persistent_defaults_path, "r")
if file ~= nil then
file:close()
load_defaults = loadfile(persistent_defaults_path)
setfenv(load_defaults, defaults)
load_defaults()
end
local i = 1
for n, v in util.orderedPairs(defaults) do
self.defaults_name[i] = n
self.defaults_value[i] = v
i = i + 1
end
self.initialized = true
end
local menu_container = CenterContainer:new{
dimen = Screen:getSize(),
}
-- FIXME:
-- in this use case (an input dialog is closed and the menu container is
-- opened immediately) we need to set the full screen dirty because
-- otherwise only the input dialog part of the screen is refreshed.
menu_container.onShow = function()
UIManager:setDirty(nil, "partial")
end
self.defaults_menu = Menu:new{
width = Screen:getWidth()-15,
height = Screen:getHeight()-15,
cface = Font:getFace("smallinfofont"),
perpage = G_reader_settings:readSetting("items_per_page") or 14,
show_parent = menu_container,
_manager = self,
}
table.insert(menu_container, self.defaults_menu)
self.defaults_menu.close_callback = function()
UIManager:close(menu_container)
end
local cancel_button = {
text = _("Cancel"),
enabled = true,
callback = function()
self:close()
UIManager:show(menu_container)
end,
}
for i=1, #self.defaults_name do
self.changed[i] = false
local setting_name = self.defaults_name[i]
local setting_type = type(_G[setting_name])
if setting_type == "boolean" then
local editBoolean = function()
self.set_dialog = InputDialog:new{
title = setting_name,
input = tostring(self.defaults_value[i]),
buttons = {
{
cancel_button,
{
text = "true",
enabled = true,
callback = function()
self.defaults_value[i] = true
_G[setting_name] = true
self.settings_changed = true
self.changed[i] = true
self.results[i].text = self:build_setting(i)
self:close()
self.defaults_menu:switchItemTable("Defaults", self.results, i)
UIManager:show(menu_container)
end
},
{
text = "false",
enabled = true,
callback = function()
self.defaults_value[i] = false
_G[setting_name] = false
self.settings_changed = true
self.changed[i] = true
self.results[i].text = self:build_setting(i)
self.defaults_menu:switchItemTable("Defaults", self.results, i)
self:close()
UIManager:show(menu_container)
end
},
},
},
input_type = setting_type,
width = Screen:getWidth() * 0.95,
}
UIManager:show(self.set_dialog)
self.set_dialog:onShowKeyboard()
end
table.insert(self.results, {
text = self:build_setting(i),
callback = editBoolean
})
elseif setting_type == "table" then
local editTable = function()
local fields = {}
for k, v in util.orderedPairs(_G[setting_name]) do
table.insert(fields, {
text = tostring(k) .. " = " .. tostring(v),
hint = "",
})
end
self.set_dialog = MultiInputDialog:new{
title = setting_name,
fields = fields,
buttons = {
{
cancel_button,
{
text = _("OK"),
enabled = true,
is_enter_default = true,
callback = function()
local new_table = {}
for _, field in ipairs(MultiInputDialog:getFields()) do
local key, value = field:match("^[^= ]+"), field:match("[^= ]+$")
new_table[tonumber(key) or key] = tonumber(value) or value
end
_G[setting_name] = new_table
self.defaults_value[i] = _G[setting_name]
self.settings_changed = true
self.changed[i] = true
self.results[i].text = self:build_setting(i)
self:close()
self.defaults_menu:switchItemTable("Defaults", self.results, i)
UIManager:show(menu_container)
end,
},
},
},
width = Screen:getWidth() * 0.95,
height = Screen:getHeight() * 0.2,
}
UIManager:show(self.set_dialog)
self.set_dialog:onShowKeyboard()
end
table.insert(self.results, {
text = self:build_setting(i),
callback = editTable
})
else
local editNumStr = function()
self.set_dialog = InputDialog:new{
title = setting_name,
input = tostring(self.defaults_value[i]),
buttons = {
{
cancel_button,
{
text = _("OK"),
is_enter_default = true,
enabled = true,
callback = function()
local new_value = self.set_dialog:getInputValue()
if _G[setting_name] ~= new_value then
_G[setting_name] = new_value
self.defaults_value[i] = new_value
self.settings_changed = true
self.changed[i] = true
self.results[i].text = self:build_setting(i)
end
self:close()
self.defaults_menu:switchItemTable("Defaults", self.results, i)
UIManager:show(menu_container)
end,
},
},
},
input_type = setting_type,
width = Screen:getWidth() * 0.95,
}
UIManager:show(self.set_dialog)
self.set_dialog:onShowKeyboard()
end
table.insert(self.results, {
text = self:build_setting(i),
callback = editNumStr
})
end
end
self.defaults_menu:switchItemTable("Defaults", self.results)
UIManager:show(menu_container)
end
function SetDefaults:close()
UIManager:close(self.set_dialog)
end
function SetDefaults:ConfirmSave()
UIManager:show(ConfirmBox:new{
text = _('Are you sure you want to save the settings to "defaults.persistent.lua"?'),
ok_callback = function()
self:saveSettings()
end,
})
end
function SetDefaults:build_setting(j)
local setting_name = self.defaults_name[j]
local ret = setting_name .. " = "
if type(_G[setting_name]) == "boolean" then
return ret .. tostring(self.defaults_value[j])
elseif type(_G[setting_name]) == "table" then
return ret .. "{...}"
elseif tonumber(self.defaults_value[j]) then
return ret .. tostring(tonumber(self.defaults_value[j]))
else
return ret .. "\"" .. tostring(self.defaults_value[j]) .. "\""
end
end
function SetDefaults:saveSettings()
self.results = {}
local persisted_defaults = {}
local file = io.open(persistent_defaults_path, "r")
if file ~= nil then
file:close()
local load_defaults = loadfile(persistent_defaults_path)
setfenv(load_defaults, persisted_defaults)
load_defaults()
end
local checked = {}
for j=1, #self.defaults_name do
if not self.changed[j] then checked[j] = true end
end
-- load default value for defaults
local defaults = {}
local load_defaults = loadfile(defaults_path)
setfenv(load_defaults, defaults)
load_defaults()
-- handle case "found in persistent" and changed, replace/delete it
for k, v in pairs(persisted_defaults) do
for j=1, #self.defaults_name do
if not checked[j]
and k == self.defaults_name[j] then
-- remove from persist if value got reverted back to the
-- default one
if defaults[k] == self.defaults_value[j] then
persisted_defaults[k] = nil
else
persisted_defaults[k] = self.defaults_value[j]
end
checked[j] = true
end
end
end
-- handle case "not in persistent and different in non-persistent", add to
-- persistent
for j=1, #self.defaults_name do
if not checked[j] then
persisted_defaults[self.defaults_name[j]] = self.defaults_value[j]
end
end
file = io.open(persistent_defaults_path, "w")
if file then
file:write("-- For configuration changes that persists between updates\n")
for k, v in pairs(persisted_defaults) do
local line = {}
table.insert(line, k)
table.insert(line, " = ")
table.insert(line, dump(v))
table.insert(line, "\n")
file:write(table.concat(line))
end
file:close()
UIManager:show(InfoMessage:new{
text = _("Default settings saved."),
})
end
self.settings_changed = false
end
return SetDefaults