2017-04-29 08:38:09 +00:00
|
|
|
local CenterContainer = require("ui/widget/container/centercontainer")
|
|
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
2019-09-26 21:13:35 +00:00
|
|
|
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")
|
[RFC] Pagination UI shenanigans (#7335)
* Menu/KeyValuePage/ReaderGoTo: Unify the dialogs. (Generally, "Enter page number" as title, and "Go to page" as OK button).
* Allow *tapping* on pagination buttons, too. Added spacers around the text to accommodate for that.
* Disable input handlers when <= 1 pages, while still printing the label in black.
* Always display both the label and the chevrons, even on single page content. (Menu being an exception, because it can handle showing no content at all, in which case we hide the chevrons).
* KVP: Tweak the pagination buttons layout in order to have consistent centering, regardless of whether the return arrow is enabled or not. (Also, match Menu's layout, more or less).
* Menu: Minor layout tweaks to follow the KVP tweaks above. Fixes, among possibly other things, buttons in (non-FM) "List" menus overlapping the final entry (e.g., OPDS), and popout menus with a border being misaligned (e.g., Calibre, Find a file).
* CalendarView: Minor layout tweaks to follow the KVP tweaks. Ensures the pagination buttons are laid out in the same way as everywhere else (they used to be a wee bit higher).
2021-02-25 04:15:23 +00:00
|
|
|
local Size = require("ui/size")
|
2015-06-15 08:46:43 +00:00
|
|
|
local UIManager = require("ui/uimanager")
|
2019-09-26 21:13:35 +00:00
|
|
|
local logger = require("logger")
|
2022-09-27 23:10:50 +00:00
|
|
|
local ffiUtil = require("ffi/util")
|
|
|
|
local util = require("util")
|
2014-09-05 13:05:20 +00:00
|
|
|
local _ = require("gettext")
|
2017-04-29 08:38:09 +00:00
|
|
|
local Screen = require("device").screen
|
2016-05-02 02:39:31 +00:00
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-09-27 23:10:50 +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...
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
-- Then deal with our child widgets and our internal variables
|
2021-09-17 17:36:57 +00:00
|
|
|
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)
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
-- 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,
|
|
|
|
}
|
2019-09-26 21:13:35 +00:00
|
|
|
end
|
2022-09-27 23:10:50 +00:00
|
|
|
for k, v in pairs(rw_defaults) do
|
|
|
|
self.state[k].value = v
|
|
|
|
self.state[k].custom = true
|
2019-09-26 21:13:35 +00:00
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
-- Prepare our menu entires
|
|
|
|
self.menu_entries = {}
|
2014-08-11 08:39:49 +00:00
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
local set_dialog
|
2016-05-02 02:39:31 +00:00
|
|
|
local cancel_button = {
|
|
|
|
text = _("Cancel"),
|
2022-03-04 20:20:00 +00:00
|
|
|
id = "close",
|
2016-05-02 02:39:31 +00:00
|
|
|
enabled = true,
|
|
|
|
callback = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:close(set_dialog)
|
2016-05-02 02:39:31 +00:00
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|
2016-05-02 02:39:31 +00:00
|
|
|
local editBoolean = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
set_dialog = InputDialog:new{
|
|
|
|
title = k,
|
|
|
|
input = tostring(self.state[k].value),
|
2016-05-02 02:39:31 +00:00
|
|
|
buttons = {
|
|
|
|
{
|
|
|
|
cancel_button,
|
2022-09-27 23:10:50 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
},
|
2016-05-02 02:39:31 +00:00
|
|
|
{
|
|
|
|
text = "true",
|
|
|
|
enabled = true,
|
|
|
|
callback = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:close(set_dialog)
|
|
|
|
self:update_menu_entry(k, true, value_type)
|
2016-05-02 02:39:31 +00:00
|
|
|
end
|
|
|
|
},
|
|
|
|
{
|
|
|
|
text = "false",
|
|
|
|
enabled = true,
|
|
|
|
callback = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:close(set_dialog)
|
|
|
|
self:update_menu_entry(k, false, value_type)
|
2016-05-02 02:39:31 +00:00
|
|
|
end
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2022-09-27 23:10:50 +00:00
|
|
|
input_type = value_type,
|
2021-09-17 17:36:57 +00:00
|
|
|
width = self.dialog_width,
|
2016-05-02 02:39:31 +00:00
|
|
|
}
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:show(set_dialog)
|
|
|
|
set_dialog:onShowKeyboard()
|
2016-05-02 02:39:31 +00:00
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
table.insert(self.menu_entries, {
|
|
|
|
text = self:gen_menu_entry(k, self.state[k].value, value_type),
|
|
|
|
bold = self.state[k].custom,
|
2016-05-02 02:39:31 +00:00
|
|
|
callback = editBoolean
|
|
|
|
})
|
2022-09-27 23:10:50 +00:00
|
|
|
elseif value_type == "table" then
|
2016-05-02 02:39:31 +00:00
|
|
|
local editTable = function()
|
|
|
|
local fields = {}
|
2022-09-27 23:10:50 +00:00
|
|
|
for key, value in ffiUtil.orderedPairs(self.state[k].value) do
|
2016-05-02 02:39:31 +00:00
|
|
|
table.insert(fields, {
|
2022-09-27 23:10:50 +00:00
|
|
|
text = tostring(key) .. " = " .. tostring(value),
|
|
|
|
input_type = type(value),
|
2016-05-02 02:39:31 +00:00
|
|
|
hint = "",
|
2018-07-07 22:45:27 +00:00
|
|
|
padding = Screen:scaleBySize(2),
|
|
|
|
margin = Screen:scaleBySize(2),
|
2016-05-02 02:39:31 +00:00
|
|
|
})
|
|
|
|
end
|
2022-09-27 23:10:50 +00:00
|
|
|
set_dialog = MultiInputDialog:new{
|
|
|
|
title = k,
|
2016-05-02 02:39:31 +00:00
|
|
|
fields = fields,
|
|
|
|
buttons = {
|
|
|
|
{
|
|
|
|
cancel_button,
|
2022-09-27 23:10:50 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
},
|
2014-08-16 20:31:32 +00:00
|
|
|
{
|
2016-05-02 02:39:31 +00:00
|
|
|
text = _("OK"),
|
|
|
|
enabled = true,
|
2016-05-26 06:09:49 +00:00
|
|
|
is_enter_default = true,
|
2016-05-02 02:39:31 +00:00
|
|
|
callback = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:close(set_dialog)
|
2016-05-02 02:39:31 +00:00
|
|
|
local new_table = {}
|
2022-10-06 15:11:47 +00:00
|
|
|
for _, field in ipairs(set_dialog:getFields()) do
|
2016-10-15 00:03:44 +00:00
|
|
|
local key, value = field:match("^[^= ]+"), field:match("[^= ]+$")
|
|
|
|
new_table[tonumber(key) or key] = tonumber(value) or value
|
2014-08-26 00:59:24 +00:00
|
|
|
end
|
2022-09-27 23:10:50 +00:00
|
|
|
self:update_menu_entry(k, new_table, value_type)
|
2016-05-02 02:39:31 +00:00
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-09-17 17:36:57 +00:00
|
|
|
width = self.dialog_width,
|
2016-05-02 02:39:31 +00:00
|
|
|
}
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:show(set_dialog)
|
|
|
|
set_dialog:onShowKeyboard()
|
2016-05-02 02:39:31 +00:00
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
table.insert(self.menu_entries, {
|
|
|
|
text = self:gen_menu_entry(k, self.state[k].value, value_type),
|
|
|
|
bold = self.state[k].custom,
|
2016-05-02 02:39:31 +00:00
|
|
|
callback = editTable
|
|
|
|
})
|
|
|
|
else
|
|
|
|
local editNumStr = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
set_dialog = InputDialog:new{
|
|
|
|
title = k,
|
|
|
|
input = tostring(self.state[k].value),
|
2016-05-02 02:39:31 +00:00
|
|
|
buttons = {
|
|
|
|
{
|
|
|
|
cancel_button,
|
2022-09-27 23:10:50 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
},
|
2016-05-02 02:39:31 +00:00
|
|
|
{
|
|
|
|
text = _("OK"),
|
2016-05-26 06:09:49 +00:00
|
|
|
is_enter_default = true,
|
2016-05-02 02:39:31 +00:00
|
|
|
enabled = true,
|
|
|
|
callback = function()
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:close(set_dialog)
|
|
|
|
local new_value = set_dialog:getInputValue()
|
|
|
|
self:update_menu_entry(k, new_value, value_type)
|
2016-05-02 02:39:31 +00:00
|
|
|
end,
|
2014-08-11 08:39:49 +00:00
|
|
|
},
|
2014-08-16 20:31:32 +00:00
|
|
|
},
|
2016-05-02 02:39:31 +00:00
|
|
|
},
|
2022-09-27 23:10:50 +00:00
|
|
|
input_type = value_type,
|
2021-09-17 17:36:57 +00:00
|
|
|
width = self.dialog_width,
|
2016-05-02 02:39:31 +00:00
|
|
|
}
|
2022-09-27 23:10:50 +00:00
|
|
|
UIManager:show(set_dialog)
|
|
|
|
set_dialog:onShowKeyboard()
|
2014-08-26 00:59:24 +00:00
|
|
|
end
|
2016-05-02 02:39:31 +00:00
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
table.insert(self.menu_entries, {
|
|
|
|
text = self:gen_menu_entry(k, self.state[k].value, value_type),
|
|
|
|
bold = self.state[k].custom,
|
2016-05-02 02:39:31 +00:00
|
|
|
callback = editNumStr
|
|
|
|
})
|
2014-08-16 20:31:32 +00:00
|
|
|
end
|
2014-08-11 08:39:49 +00:00
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
-- 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
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
table.insert(self, self.defaults_menu)
|
2014-08-11 08:39:49 +00:00
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|
2016-05-02 02:39:31 +00:00
|
|
|
return ret .. "{...}"
|
2022-09-27 23:10:50 +00:00
|
|
|
elseif tonumber(v) then
|
|
|
|
return ret .. tostring(tonumber(v))
|
2014-08-19 20:50:20 +00:00
|
|
|
else
|
2022-09-27 23:10:50 +00:00
|
|
|
return ret .. "\"" .. tostring(v) .. "\""
|
2014-08-19 20:50:20 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|
2022-09-27 23:10:50 +00:00
|
|
|
self.defaults_menu:switchItemTable(nil, self.menu_entries, idx)
|
|
|
|
end
|
2014-08-11 08:39:49 +00:00
|
|
|
|
2022-09-27 23:10:50 +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
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
-- And flush to disk
|
|
|
|
G_defaults:flush()
|
|
|
|
UIManager:show(InfoMessage:new{
|
|
|
|
text = _("Default settings saved."),
|
|
|
|
})
|
2014-08-11 08:39:49 +00:00
|
|
|
end
|
2016-05-02 02:39:31 +00:00
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
function SetDefaultsWidget:saveBeforeExit(callback)
|
2019-09-26 21:13:35 +00:00
|
|
|
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{
|
2022-09-27 23:10:50 +00:00
|
|
|
dismissable = false,
|
2019-09-26 21:13:35 +00:00
|
|
|
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
|
|
|
|
|
2022-09-27 23:10:50 +00:00
|
|
|
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
|