mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
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.
388 lines
14 KiB
Lua
388 lines
14 KiB
Lua
--[[
|
|
This plugin implements KOReader integration with *some* calibre features:
|
|
|
|
- metadata search
|
|
- wireless transfers
|
|
|
|
This module handles the UI part of the plugin.
|
|
--]]
|
|
|
|
local BD = require("ui/bidi")
|
|
local CalibreExtensions = require("extensions")
|
|
local CalibreSearch = require("search")
|
|
local CalibreWireless = require("wireless")
|
|
local Dispatcher = require("dispatcher")
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local LuaSettings = require("luasettings")
|
|
local UIManager = require("ui/uimanager")
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
|
local _ = require("gettext")
|
|
local C_ = _.pgettext
|
|
local T = require("ffi/util").template
|
|
|
|
local Calibre = WidgetContainer:extend{
|
|
name = "calibre",
|
|
is_doc_only = false,
|
|
}
|
|
|
|
function Calibre:onCalibreSearch()
|
|
CalibreSearch:ShowSearch()
|
|
return true
|
|
end
|
|
|
|
function Calibre:onCalibreBrowseTags()
|
|
CalibreSearch.search_value = ""
|
|
CalibreSearch:find("tags", 1)
|
|
return true
|
|
end
|
|
|
|
function Calibre:onCalibreBrowseSeries()
|
|
CalibreSearch.search_value = ""
|
|
CalibreSearch:find("series", 1)
|
|
return true
|
|
end
|
|
|
|
function Calibre:onNetworkDisconnected()
|
|
self:closeWirelessConnection()
|
|
end
|
|
|
|
function Calibre:onSuspend()
|
|
self:closeWirelessConnection()
|
|
end
|
|
|
|
function Calibre:onClose()
|
|
self:closeWirelessConnection()
|
|
end
|
|
|
|
function Calibre:closeWirelessConnection()
|
|
if CalibreWireless.calibre_socket then
|
|
CalibreWireless:disconnect()
|
|
end
|
|
end
|
|
|
|
function Calibre:onDispatcherRegisterActions()
|
|
Dispatcher:registerAction("calibre_search", { category="none", event="CalibreSearch", title=_("Calibre metadata search"), general=true,})
|
|
Dispatcher:registerAction("calibre_browse_tags", { category="none", event="CalibreBrowseTags", title=_("Browse all calibre tags"), general=true,})
|
|
Dispatcher:registerAction("calibre_browse_series", { category="none", event="CalibreBrowseSeries", title=_("Browse all calibre series"), general=true, separator=true,})
|
|
end
|
|
|
|
function Calibre:init()
|
|
CalibreWireless:init()
|
|
self:onDispatcherRegisterActions()
|
|
self.ui.menu:registerToMainMenu(self)
|
|
end
|
|
|
|
function Calibre:addToMainMenu(menu_items)
|
|
menu_items.calibre = {
|
|
-- its name is "calibre", but all our top menu items are uppercase.
|
|
text = _("Calibre"),
|
|
sub_item_table = {
|
|
{
|
|
text_func = function()
|
|
if CalibreWireless.calibre_socket then
|
|
return _("Disconnect")
|
|
else
|
|
return _("Connect")
|
|
end
|
|
end,
|
|
separator = true,
|
|
enabled_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_wireless")
|
|
end,
|
|
callback = function()
|
|
if not CalibreWireless.calibre_socket then
|
|
CalibreWireless:connect()
|
|
else
|
|
CalibreWireless:disconnect()
|
|
end
|
|
end,
|
|
},
|
|
{ text = _("Search settings"),
|
|
keep_menu_open = true,
|
|
sub_item_table = self:getSearchMenuTable(),
|
|
},
|
|
{
|
|
text = _("Wireless settings"),
|
|
keep_menu_open = true,
|
|
sub_item_table = self:getWirelessMenuTable(),
|
|
},
|
|
}
|
|
}
|
|
-- insert the metadata search
|
|
if G_reader_settings:isTrue("calibre_search_from_reader") or not self.ui.view then
|
|
menu_items.find_book_in_calibre_catalog = {
|
|
text = _("Calibre metadata search"),
|
|
callback = function()
|
|
CalibreSearch:ShowSearch()
|
|
end
|
|
}
|
|
end
|
|
end
|
|
|
|
-- search options available from UI
|
|
function Calibre:getSearchMenuTable()
|
|
return {
|
|
{
|
|
text = _("Manage libraries"),
|
|
separator = true,
|
|
keep_menu_open = true,
|
|
sub_item_table_func = function()
|
|
local result = {}
|
|
-- append previous scanned dirs to the list.
|
|
local cache = LuaSettings:open(CalibreSearch.cache_libs.path)
|
|
for path, _ in pairs(cache.data) do
|
|
table.insert(result, {
|
|
text = path,
|
|
keep_menu_open = true,
|
|
checked_func = function()
|
|
return cache:isTrue(path)
|
|
end,
|
|
callback = function()
|
|
cache:toggle(path)
|
|
cache:flush()
|
|
CalibreSearch:invalidateCache()
|
|
end,
|
|
})
|
|
end
|
|
-- if there's no result then no libraries are stored
|
|
if #result == 0 then
|
|
table.insert(result, {
|
|
text = _("No calibre libraries"),
|
|
enabled = false
|
|
})
|
|
end
|
|
table.insert(result, 1, {
|
|
text = _("Rescan disk for calibre libraries"),
|
|
separator = true,
|
|
callback = function()
|
|
CalibreSearch:prompt()
|
|
end,
|
|
})
|
|
return result
|
|
end,
|
|
},
|
|
{
|
|
text = _("Enable searches in the reader"),
|
|
checked_func = function()
|
|
return G_reader_settings:isTrue("calibre_search_from_reader")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:toggle("calibre_search_from_reader")
|
|
UIManager:show(InfoMessage:new{
|
|
text = _("This will take effect on next restart."),
|
|
})
|
|
end,
|
|
},
|
|
{
|
|
text = _("Store metadata in cache"),
|
|
checked_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_search_cache_metadata")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_search_cache_metadata")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Case sensitive search"),
|
|
checked_func = function()
|
|
return not G_reader_settings:nilOrTrue("calibre_search_case_insensitive")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_search_case_insensitive")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Search by title"),
|
|
checked_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_search_find_by_title")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_search_find_by_title")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Search by authors"),
|
|
checked_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_search_find_by_authors")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_search_find_by_authors")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Search by path"),
|
|
checked_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_search_find_by_path")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_search_find_by_path")
|
|
end,
|
|
},
|
|
}
|
|
end
|
|
|
|
-- wireless options available from UI
|
|
function Calibre:getWirelessMenuTable()
|
|
local function isEnabled()
|
|
local enabled = G_reader_settings:nilOrTrue("calibre_wireless")
|
|
return enabled and not CalibreWireless.calibre_socket
|
|
end
|
|
|
|
local t = {
|
|
{
|
|
text = _("Enable wireless client"),
|
|
separator = true,
|
|
enabled_func = function()
|
|
return not CalibreWireless.calibre_socket
|
|
end,
|
|
checked_func = function()
|
|
return G_reader_settings:nilOrTrue("calibre_wireless")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:flipNilOrTrue("calibre_wireless")
|
|
end,
|
|
},
|
|
{
|
|
text = _("Set password"),
|
|
enabled_func = isEnabled,
|
|
callback = function()
|
|
CalibreWireless:setPassword()
|
|
end,
|
|
},
|
|
{
|
|
text = _("Set inbox folder"),
|
|
enabled_func = isEnabled,
|
|
callback = function()
|
|
CalibreWireless:setInboxDir()
|
|
end,
|
|
},
|
|
{
|
|
text_func = function()
|
|
local address = _("automatic")
|
|
if G_reader_settings:has("calibre_wireless_url") then
|
|
address = G_reader_settings:readSetting("calibre_wireless_url")
|
|
address = string.format("%s:%s", address["address"], address["port"])
|
|
end
|
|
return T(_("Server address (%1)"), BD.ltr(address))
|
|
end,
|
|
enabled_func = isEnabled,
|
|
sub_item_table = {
|
|
{
|
|
text = C_("Configuration type", "Automatic"),
|
|
checked_func = function()
|
|
return G_reader_settings:hasNot("calibre_wireless_url")
|
|
end,
|
|
callback = function()
|
|
G_reader_settings:delSetting("calibre_wireless_url")
|
|
end,
|
|
},
|
|
{
|
|
text = C_("Configuration type", "Manual"),
|
|
checked_func = function()
|
|
return G_reader_settings:has("calibre_wireless_url")
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
local MultiInputDialog = require("ui/widget/multiinputdialog")
|
|
local url_dialog
|
|
local calibre_url = G_reader_settings:readSetting("calibre_wireless_url")
|
|
local calibre_url_address, calibre_url_port
|
|
if calibre_url then
|
|
calibre_url_address = calibre_url["address"]
|
|
calibre_url_port = calibre_url["port"]
|
|
end
|
|
url_dialog = MultiInputDialog:new{
|
|
title = _("Set custom calibre address"),
|
|
fields = {
|
|
{
|
|
text = calibre_url_address,
|
|
input_type = "string",
|
|
hint = _("IP Address"),
|
|
},
|
|
{
|
|
text = calibre_url_port,
|
|
input_type = "number",
|
|
hint = _("Port"),
|
|
},
|
|
},
|
|
buttons = {
|
|
{
|
|
{
|
|
text = _("Cancel"),
|
|
id = "close",
|
|
callback = function()
|
|
UIManager:close(url_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("OK"),
|
|
callback = function()
|
|
local fields = url_dialog:getFields()
|
|
if fields[1] ~= "" then
|
|
local port = tonumber(fields[2])
|
|
if not port or port < 1 or port > 65355 then
|
|
--default port
|
|
port = 9090
|
|
end
|
|
G_reader_settings:saveSetting("calibre_wireless_url", {address = fields[1], port = port })
|
|
end
|
|
UIManager:close(url_dialog)
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
UIManager:show(url_dialog)
|
|
url_dialog:onShowKeyboard()
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if not CalibreExtensions:isCustom() then
|
|
table.insert(t, 2, {
|
|
text = _("File formats"),
|
|
enabled_func = isEnabled,
|
|
sub_item_table_func = function()
|
|
local submenu = {
|
|
{
|
|
text = _("About formats"),
|
|
keep_menu_open = true,
|
|
separator = true,
|
|
callback = function()
|
|
UIManager:show(InfoMessage:new{
|
|
text = string.format("%s: %s \n\n%s",
|
|
_("Supported file formats"),
|
|
CalibreExtensions:getInfo(),
|
|
_("Unsupported formats will be converted by calibre to the first format of the list."))
|
|
})
|
|
end,
|
|
}
|
|
}
|
|
|
|
for i, v in ipairs(CalibreExtensions.outputs) do
|
|
table.insert(submenu, {})
|
|
submenu[i+1].text = v
|
|
submenu[i+1].checked_func = function()
|
|
if v == CalibreExtensions.default_output then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
submenu[i+1].callback = function()
|
|
if type(v) == "string" and v ~= CalibreExtensions.default_output then
|
|
CalibreExtensions.default_output = v
|
|
G_reader_settings:saveSetting("calibre_wireless_default_format", CalibreExtensions.default_output)
|
|
end
|
|
end
|
|
end
|
|
return submenu
|
|
end,
|
|
})
|
|
end
|
|
return t
|
|
end
|
|
|
|
return Calibre
|