2020-02-03 19:08:18 +00:00
|
|
|
local BD = require("ui/bidi")
|
2019-11-05 23:17:28 +00:00
|
|
|
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
2020-02-03 19:08:18 +00:00
|
|
|
local Device = require("device")
|
2019-11-05 23:17:28 +00:00
|
|
|
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
2020-02-03 19:08:18 +00:00
|
|
|
local InfoMessage = require("ui/widget/infomessage")
|
2019-11-05 23:17:28 +00:00
|
|
|
local Menu = require("ui/widget/menu")
|
|
|
|
local ReadCollection = require("readcollection")
|
|
|
|
local UIManager = require("ui/uimanager")
|
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
|
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
2019-11-05 23:17:28 +00:00
|
|
|
local Screen = require("device").screen
|
2022-12-25 07:46:44 +00:00
|
|
|
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
2020-02-03 19:08:18 +00:00
|
|
|
local BaseUtil = require("ffi/util")
|
|
|
|
local util = require("util")
|
2019-11-05 23:17:28 +00:00
|
|
|
local _ = require("gettext")
|
2020-09-15 18:39:32 +00:00
|
|
|
local T = BaseUtil.template
|
2019-11-05 23:17:28 +00:00
|
|
|
|
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
|
|
|
local FileManagerCollection = WidgetContainer:extend{
|
2019-11-05 23:17:28 +00:00
|
|
|
coll_menu_title = _("Favorites"),
|
|
|
|
}
|
|
|
|
|
|
|
|
function FileManagerCollection:init()
|
|
|
|
self.ui.menu:registerToMainMenu(self)
|
|
|
|
end
|
|
|
|
|
|
|
|
function FileManagerCollection:addToMainMenu(menu_items)
|
|
|
|
menu_items.collections = {
|
|
|
|
text = self.coll_menu_title,
|
|
|
|
callback = function()
|
|
|
|
self:onShowColl("favorites")
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function FileManagerCollection:updateItemTable()
|
|
|
|
-- Try to stay on current page.
|
|
|
|
local select_number = nil
|
|
|
|
if self.coll_menu.page and self.coll_menu.perpage then
|
|
|
|
select_number = (self.coll_menu.page - 1) * self.coll_menu.perpage + 1
|
|
|
|
end
|
|
|
|
self.coll_menu:switchItemTable(self.coll_menu_title,
|
|
|
|
ReadCollection:prepareList(self.coll_menu.collection), select_number)
|
|
|
|
end
|
|
|
|
|
|
|
|
function FileManagerCollection:onMenuHold(item)
|
2023-02-07 02:46:09 +00:00
|
|
|
local readerui_instance = require("apps/reader/readerui"):_getRunningInstance()
|
|
|
|
local currently_opened_file = readerui_instance and readerui_instance.document and readerui_instance.document.file
|
2019-11-05 23:17:28 +00:00
|
|
|
self.collfile_dialog = nil
|
2023-02-04 21:05:06 +00:00
|
|
|
local function status_button_callback()
|
|
|
|
self._manager:updateItemTable()
|
|
|
|
UIManager:close(self.collfile_dialog)
|
2023-02-04 20:32:43 +00:00
|
|
|
end
|
2019-11-05 23:17:28 +00:00
|
|
|
local buttons = {
|
2023-02-10 11:14:21 +00:00
|
|
|
filemanagerutil.genStatusButtonsRow(item.file, status_button_callback),
|
2022-12-25 07:46:44 +00:00
|
|
|
{},
|
2019-11-05 23:17:28 +00:00
|
|
|
{
|
2023-02-09 03:55:13 +00:00
|
|
|
filemanagerutil.genResetSettingsButton(item.file, currently_opened_file, status_button_callback),
|
2022-12-25 08:23:43 +00:00
|
|
|
{
|
|
|
|
text = _("Remove from collection"),
|
|
|
|
callback = function()
|
|
|
|
ReadCollection:removeItem(item.file, self._manager.coll_menu.collection)
|
|
|
|
self._manager:updateItemTable()
|
|
|
|
UIManager:close(self.collfile_dialog)
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
text = _("Sort collection"),
|
2019-11-05 23:17:28 +00:00
|
|
|
callback = function()
|
|
|
|
UIManager:close(self.collfile_dialog)
|
|
|
|
local item_table = {}
|
|
|
|
for i=1, #self._manager.coll_menu.item_table do
|
|
|
|
table.insert(item_table, {text = self._manager.coll_menu.item_table[i].text, label = self._manager.coll_menu.item_table[i].file})
|
|
|
|
end
|
|
|
|
local SortWidget = require("ui/widget/sortwidget")
|
|
|
|
local sort_item
|
|
|
|
sort_item = SortWidget:new{
|
|
|
|
title = _("Sort favorites"),
|
|
|
|
item_table = item_table,
|
|
|
|
callback = function()
|
|
|
|
local new_order_table = {}
|
|
|
|
for i=1, #sort_item.item_table do
|
|
|
|
table.insert(new_order_table, {
|
|
|
|
file = sort_item.item_table[i].label,
|
|
|
|
order = i
|
|
|
|
})
|
|
|
|
end
|
|
|
|
ReadCollection:writeCollection(new_order_table, self._manager.coll_menu.collection)
|
|
|
|
self._manager:updateItemTable()
|
|
|
|
end
|
|
|
|
}
|
|
|
|
UIManager:show(sort_item)
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
text = _("Book information"),
|
2022-12-24 08:28:02 +00:00
|
|
|
id = "book_information", -- used by covermenu
|
2019-11-05 23:17:28 +00:00
|
|
|
enabled = FileManagerBookInfo:isSupported(item.file),
|
|
|
|
callback = function()
|
|
|
|
FileManagerBookInfo:show(item.file)
|
|
|
|
UIManager:close(self.collfile_dialog)
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2020-02-03 19:08:18 +00:00
|
|
|
-- NOTE: Duplicated from frontend/apps/filemanager/filemanager.lua
|
2020-07-09 16:11:56 +00:00
|
|
|
if Device:canExecuteScript(item.file) then
|
2020-02-03 19:08:18 +00:00
|
|
|
table.insert(buttons, {
|
|
|
|
{
|
|
|
|
-- @translators This is the script's programming language (e.g., shell or python)
|
|
|
|
text = T(_("Execute %1 script"), util.getScriptType(item.file)),
|
|
|
|
enabled = true,
|
|
|
|
callback = function()
|
|
|
|
UIManager:close(self.collfile_dialog)
|
|
|
|
local script_is_running_msg = InfoMessage:new{
|
|
|
|
-- @translators %1 is the script's programming language (e.g., shell or python), %2 is the filename
|
2020-02-04 18:22:33 +00:00
|
|
|
text = T(_("Running %1 script %2…"), util.getScriptType(item.file), BD.filename(BaseUtil.basename(item.file))),
|
2020-02-03 19:08:18 +00:00
|
|
|
}
|
|
|
|
UIManager:show(script_is_running_msg)
|
|
|
|
UIManager:scheduleIn(0.5, function()
|
|
|
|
local rv = os.execute(BaseUtil.realpath(item.file))
|
|
|
|
UIManager:close(script_is_running_msg)
|
|
|
|
if rv == 0 then
|
|
|
|
UIManager:show(InfoMessage:new{
|
|
|
|
text = _("The script exited successfully."),
|
|
|
|
})
|
|
|
|
else
|
|
|
|
UIManager:show(InfoMessage:new{
|
|
|
|
text = T(_("The script returned a non-zero status code: %1!"), bit.rshift(rv, 8)),
|
2020-12-19 11:18:30 +00:00
|
|
|
icon = "notice-warning",
|
2020-02-03 19:08:18 +00:00
|
|
|
})
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2019-11-05 23:17:28 +00:00
|
|
|
self.collfile_dialog = ButtonDialogTitle:new{
|
|
|
|
title = item.text:match("([^/]+)$"),
|
|
|
|
title_align = "center",
|
|
|
|
buttons = buttons,
|
|
|
|
}
|
|
|
|
UIManager:show(self.collfile_dialog)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2021-04-09 21:12:15 +00:00
|
|
|
function FileManagerCollection:MenuSetRotationModeHandler(rotation)
|
|
|
|
if rotation ~= nil and rotation ~= Screen:getRotationMode() then
|
|
|
|
UIManager:close(self._manager.coll_menu)
|
|
|
|
if self._manager.ui.view and self._manager.ui.view.onSetRotationMode then
|
|
|
|
self._manager.ui.view:onSetRotationMode(rotation)
|
|
|
|
elseif self._manager.ui.onSetRotationMode then
|
|
|
|
self._manager.ui:onSetRotationMode(rotation)
|
|
|
|
else
|
|
|
|
Screen:setRotationMode(rotation)
|
|
|
|
end
|
|
|
|
self._manager:onShowColl()
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-11-05 23:17:28 +00:00
|
|
|
function FileManagerCollection:onShowColl(collection)
|
|
|
|
self.coll_menu = Menu:new{
|
|
|
|
ui = self.ui,
|
|
|
|
width = Screen:getWidth(),
|
|
|
|
height = Screen:getHeight(),
|
|
|
|
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
|
|
|
is_borderless = true,
|
|
|
|
is_popout = false,
|
|
|
|
onMenuHold = self.onMenuHold,
|
2021-04-09 21:12:15 +00:00
|
|
|
onSetRotationMode = self.MenuSetRotationModeHandler,
|
2019-11-05 23:17:28 +00:00
|
|
|
_manager = self,
|
|
|
|
collection = collection,
|
|
|
|
}
|
2021-04-09 17:40:34 +00:00
|
|
|
|
2019-11-05 23:17:28 +00:00
|
|
|
self:updateItemTable()
|
|
|
|
self.coll_menu.close_callback = function()
|
ReaderUI: Saner FM/RD lifecycle
* Ensure that going from one to the other tears down the former and
its plugins before instantiating the latter and its plugins.
UIManager: Unify Event sending & broadcasting
* Make the two behave the same way (walk the widget stack from top to
bottom), and properly handle the window stack shrinking shrinking
*and* growing.
Previously, broadcasting happened bottom-to-top and didn't really
handle the list shrinking/growing, while sending only handled the list
shrinking by a single element, and hopefully that element being the one
the event was just sent to.
These two items combined allowed us to optimize suboptimal
refresh behavior with Menu and other Menu classes when
opening/closing a document.
e.g., the "opening document" Notification is now properly regional,
and the "open last doc" option no longer flashes like a crazy person
anymore.
Plugins: Allow optimizing Menu refresh with custom menus, too.
Requires moving Menu's close_callback *after* onMenuSelect, which, eh,
probably makes sense, and is probably harmless in the grand scheme of
things.
2021-05-01 16:53:04 +00:00
|
|
|
UIManager:close(self.coll_menu)
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
UIManager:show(self.coll_menu)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return FileManagerCollection
|