mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
* [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
354 lines
13 KiB
Lua
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
|