2
0
mirror of https://github.com/koreader/koreader synced 2024-11-13 19:11:25 +00:00
koreader/frontend/apps/filemanager/filemanagersetdefaults.lua

318 lines
12 KiB
Lua
Raw Normal View History

2017-04-29 08:38:09 +00:00
local CenterContainer = require("ui/widget/container/centercontainer")
local ConfirmBox = require("ui/widget/confirmbox")
local Device = require("device")
2014-08-11 08:39:49 +00:00
local InfoMessage = require("ui/widget/infomessage")
local InputDialog = require("ui/widget/inputdialog")
2017-04-29 08:38:09 +00:00
local Menu = require("ui/widget/menu")
2014-08-25 16:03:10 +00:00
local MultiInputDialog = require("ui/widget/multiinputdialog")
local Size = require("ui/size")
local UIManager = require("ui/uimanager")
local logger = require("logger")
local ffiUtil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
2017-04-29 08:38:09 +00:00
local Screen = require("device").screen
local SetDefaultsWidget = CenterContainer:extend{
state = nil,
menu_entries = nil,
defaults_menu = nil,
2016-09-22 07:36:09 +00:00
settings_changed = false,
2014-08-11 08:39:49 +00:00
}
function SetDefaultsWidget:init()
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
-- This would usually be passed to the constructor, as CenterContainer's paintTo does *NOT* set/update self.dimen...
self.dimen = Screen:getSize()
-- Don't refresh the FM behind us. May leave stray bits of overflowed InputDialog behind in the popout border space.
self.covers_fullscreen = true
2014-08-11 08:39:49 +00:00
-- Then deal with our child widgets and our internal variables
self.screen_width = Screen:getWidth()
self.screen_height = Screen:getHeight()
self.dialog_width = math.floor(math.min(self.screen_width, self.screen_height) * 0.95)
-- Keep track of what's an actual default, and what's been customized without actually touching the real data yet...
self.state = {}
local ro_defaults, rw_defaults = G_defaults:getDataTables()
for k, v in pairs(ro_defaults) do
self.state[k] = {
idx = 1,
value = v,
custom = false,
dirty = false,
default_value = v,
}
end
for k, v in pairs(rw_defaults) do
self.state[k].value = v
self.state[k].custom = true
end
-- Prepare our menu entires
self.menu_entries = {}
2014-08-11 08:39:49 +00:00
local set_dialog
local cancel_button = {
text = _("Cancel"),
id = "close",
enabled = true,
callback = function()
UIManager:close(set_dialog)
end,
}
local i = 0
for k, t in ffiUtil.orderedPairs(self.state) do
local v = t.value
i = i + 1
self.state[k].idx = i
local value_type = type(v)
if value_type == "boolean" then
local editBoolean = function()
set_dialog = InputDialog:new{
title = k,
input = tostring(self.state[k].value),
buttons = {
{
cancel_button,
{
text = _("Default"),
enabled = self.state[k].value ~= self.state[k].default_value,
callback = function()
UIManager:close(set_dialog)
self:update_menu_entry(k, self.state[k].default_value, value_type)
end
},
{
text = "true",
enabled = true,
callback = function()
UIManager:close(set_dialog)
self:update_menu_entry(k, true, value_type)
end
},
{
text = "false",
enabled = true,
callback = function()
UIManager:close(set_dialog)
self:update_menu_entry(k, false, value_type)
end
},
},
},
input_type = value_type,
width = self.dialog_width,
}
UIManager:show(set_dialog)
set_dialog:onShowKeyboard()
end
table.insert(self.menu_entries, {
text = self:gen_menu_entry(k, self.state[k].value, value_type),
bold = self.state[k].custom,
callback = editBoolean
})
elseif value_type == "table" then
local editTable = function()
local fields = {}
for key, value in ffiUtil.orderedPairs(self.state[k].value) do
table.insert(fields, {
text = tostring(key) .. " = " .. tostring(value),
input_type = type(value),
hint = "",
padding = Screen:scaleBySize(2),
margin = Screen:scaleBySize(2),
})
end
set_dialog = MultiInputDialog:new{
title = k,
fields = fields,
buttons = {
{
cancel_button,
{
text = _("Default"),
enabled = not util.tableEquals(self.state[k].value, self.state[k].default_value),
callback = function()
UIManager:close(set_dialog)
self:update_menu_entry(k, self.state[k].default_value, value_type)
end
},
{
text = _("OK"),
enabled = true,
is_enter_default = true,
callback = function()
UIManager:close(set_dialog)
local new_table = {}
for _, field in ipairs(set_dialog:getFields()) do
local key, value = field:match("^[^= ]+"), field:match("[^= ]+$")
new_table[tonumber(key) or key] = tonumber(value) or value
end
self:update_menu_entry(k, new_table, value_type)
end,
},
},
},
width = self.dialog_width,
}
UIManager:show(set_dialog)
set_dialog:onShowKeyboard()
end
table.insert(self.menu_entries, {
text = self:gen_menu_entry(k, self.state[k].value, value_type),
bold = self.state[k].custom,
callback = editTable
})
else
local editNumStr = function()
set_dialog = InputDialog:new{
title = k,
input = tostring(self.state[k].value),
buttons = {
{
cancel_button,
{
text = _("Default"),
enabled = self.state[k].value ~= self.state[k].default_value,
callback = function()
UIManager:close(set_dialog)
self:update_menu_entry(k, self.state[k].default_value, value_type)
end
},
{
text = _("OK"),
is_enter_default = true,
enabled = true,
callback = function()
UIManager:close(set_dialog)
local new_value = set_dialog:getInputValue()
self:update_menu_entry(k, new_value, value_type)
end,
2014-08-11 08:39:49 +00:00
},
},
},
input_type = value_type,
width = self.dialog_width,
}
UIManager:show(set_dialog)
set_dialog:onShowKeyboard()
end
table.insert(self.menu_entries, {
text = self:gen_menu_entry(k, self.state[k].value, value_type),
bold = self.state[k].custom,
callback = editNumStr
})
end
2014-08-11 08:39:49 +00:00
end
-- Now that we have stuff to display, instantiate our Menu
self.defaults_menu = Menu:new{
width = self.screen_width - (Size.margin.fullscreen_popout * 2),
height = self.screen_height - (Size.margin.fullscreen_popout * 2),
show_parent = self,
item_table = self.menu_entries,
title = _("Defaults"),
}
-- Prevent menu from closing when editing a value
function self.defaults_menu:onMenuSelect(item)
item.callback()
end
self.defaults_menu.close_callback = function()
logger.dbg("Closing defaults menu")
self:saveBeforeExit()
UIManager:close(self)
end
2014-08-11 08:39:49 +00:00
table.insert(self, self.defaults_menu)
2014-08-11 08:39:49 +00:00
end
function SetDefaultsWidget:gen_menu_entry(k, v, v_type)
local ret = k .. " = "
if v_type == "boolean" then
return ret .. tostring(v)
elseif v_type == "table" then
return ret .. "{...}"
elseif tonumber(v) then
return ret .. tostring(tonumber(v))
else
return ret .. "\"" .. tostring(v) .. "\""
end
end
function SetDefaultsWidget:update_menu_entry(k, v, v_type)
local idx = self.state[k].idx
self.state[k].value = v
self.state[k].dirty = true
self.settings_changed = true
self.menu_entries[idx].text = self:gen_menu_entry(k, v, v_type)
if util.tableEquals(v, self.state[k].default_value) then
self.menu_entries[idx].bold = false
else
self.menu_entries[idx].bold = true
2014-08-11 08:39:49 +00:00
end
self.defaults_menu:switchItemTable(nil, self.menu_entries, idx)
end
2014-08-11 08:39:49 +00:00
function SetDefaultsWidget:saveSettings()
-- Update dirty keys for real
for k, t in pairs(self.state) do
if t.dirty then
G_defaults:saveSetting(k, t.value)
2014-08-11 08:39:49 +00:00
end
end
-- And flush to disk
G_defaults:flush()
UIManager:show(InfoMessage:new{
text = _("Default settings saved."),
})
2014-08-11 08:39:49 +00:00
end
function SetDefaultsWidget:saveBeforeExit(callback)
local save_text = _("Save and quit")
if Device:canRestart() then
save_text = _("Save and restart")
end
if self.settings_changed then
UIManager:show(ConfirmBox:new{
dismissable = false,
text = _("KOReader needs to be restarted to apply the new default settings."),
ok_text = save_text,
ok_callback = function()
self:saveSettings()
if Device:canRestart() then
UIManager:restartKOReader()
else
UIManager:quit()
end
end,
cancel_text = _("Discard changes"),
cancel_callback = function()
logger.info("discard defaults")
end,
})
end
end
local SetDefaults = {}
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()
SetDefaults.EditConfirmed = true
UIManager:show(SetDefaultsWidget:new{})
end,
})
else
UIManager:show(SetDefaultsWidget:new{})
end
end
2014-08-11 08:39:49 +00:00
return SetDefaults