2
0
mirror of https://github.com/koreader/koreader synced 2024-11-16 06:12:56 +00:00
koreader/frontend/apps/filemanager/filemanagerhistory.lua

271 lines
9.3 KiB
Lua
Raw Normal View History

local BD = require("ui/bidi")
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local ConfirmBox = require("ui/widget/confirmbox")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
2014-08-14 11:49:42 +00:00
local Menu = require("ui/widget/menu")
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")
local Screen = require("device").screen
local filemanagerutil = require("apps/filemanager/filemanagerutil")
2013-10-18 20:38:07 +00:00
local _ = require("gettext")
local C_ = _.pgettext
local T = require("ffi/util").template
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 FileManagerHistory = WidgetContainer:extend{
2014-03-13 13:52:43 +00:00
hist_menu_title = _("History"),
2013-08-14 09:29:05 +00:00
}
local filter_text = {
all = C_("Book status filter", "All"),
reading = C_("Book status filter", "Reading"),
abandoned = C_("Book status filter", "On hold"),
complete = C_("Book status filter", "Finished"),
deleted = C_("Book status filter", "Deleted"),
new = C_("Book status filter", "New"),
2022-03-12 10:26:11 +00:00
}
2013-08-14 09:29:05 +00:00
function FileManagerHistory:init()
2014-03-13 13:52:43 +00:00
self.ui.menu:registerToMainMenu(self)
2013-08-14 09:29:05 +00:00
end
function FileManagerHistory:addToMainMenu(menu_items)
menu_items.history = {
2016-02-17 07:10:23 +00:00
text = self.hist_menu_title,
callback = function()
self:onShowHist()
end,
}
2016-02-17 07:10:23 +00:00
end
function FileManagerHistory:fetchStatuses(count)
for _, v in ipairs(require("readhistory").hist) do
v.status = v.dim and "deleted" or filemanagerutil.getStatus(v.file)
if v.status == "new" and v.file == (self.ui.document and self.ui.document.file) then
v.status = "reading" -- file currently opened for the first time
end
if count then
self.count[v.status] = self.count[v.status] + 1
end
end
self.statuses_fetched = true
end
2016-02-17 07:10:23 +00:00
function FileManagerHistory:updateItemTable()
-- try to stay on current page
local select_number = nil
2022-03-12 10:26:11 +00:00
if self.hist_menu.page and self.hist_menu.perpage and self.hist_menu.page > 0 then
select_number = (self.hist_menu.page - 1) * self.hist_menu.perpage + 1
end
2022-03-12 10:26:11 +00:00
self.count = { all = #require("readhistory").hist,
reading = 0, abandoned = 0, complete = 0, deleted = 0, new = 0, }
local item_table = {}
for _, v in ipairs(require("readhistory").hist) do
if self.filter == "all" or v.status == self.filter then
2022-03-12 10:26:11 +00:00
table.insert(item_table, v)
end
if self.statuses_fetched then
self.count[v.status] = self.count[v.status] + 1
end
end
local title = self.hist_menu_title
if self.filter ~= "all" then
title = title .. " (" .. filter_text[self.filter] .. ": " .. self.count[self.filter] .. ")"
2022-03-12 10:26:11 +00:00
end
self.hist_menu:switchItemTable(title, item_table, select_number)
2016-02-17 07:10:23 +00:00
end
2013-08-14 09:29:05 +00:00
function FileManagerHistory:onSetDimensions(dimen)
2014-03-13 13:52:43 +00:00
self.dimen = dimen
2013-08-14 09:29:05 +00:00
end
function FileManagerHistory:onMenuHold(item)
self.histfile_dialog = nil
local function status_button_callback()
UIManager:close(self.histfile_dialog)
if self._manager.filter ~= "all" then
self._manager:fetchStatuses(false)
else
self._manager.statuses_fetched = false
end
self._manager:updateItemTable()
self._manager.files_updated = true -- sidecar folder may be created/deleted
end
local is_currently_opened = item.file == (self.ui.document and self.ui.document.file)
local buttons = {}
if not (item.dim or is_currently_opened) then
table.insert(buttons, filemanagerutil.genStatusButtonsRow(item.file, status_button_callback))
table.insert(buttons, {}) -- separator
end
table.insert(buttons, {
filemanagerutil.genResetSettingsButton(item.file, status_button_callback, is_currently_opened),
{
text = _("Remove from history"),
callback = function()
UIManager:close(self.histfile_dialog)
require("readhistory"):removeItem(item)
self._manager:updateItemTable()
end,
},
})
table.insert(buttons, {
{
text = _("Delete"),
enabled = not (item.dim or is_currently_opened),
callback = function()
local function post_delete_callback()
UIManager:close(self.histfile_dialog)
self._manager:updateItemTable()
self._manager.files_updated = true
end
local FileManager = require("apps/filemanager/filemanager")
FileManager:showDeleteFileDialog(item.file, post_delete_callback)
end,
},
{
text = _("Book information"),
id = "book_information", -- used by covermenu
enabled = not item.dim,
callback = function()
UIManager:close(self.histfile_dialog)
FileManagerBookInfo:show(item.file)
end,
},
})
table.insert(buttons, {
{
text = _("Book cover"),
id = "book_cover", -- used by covermenu
callback = function()
UIManager:close(self.histfile_dialog)
FileManagerBookInfo:onShowBookCover(item.file)
end,
},
{
text = _("Book description"),
id = "book_description", -- used by covermenu
callback = function()
UIManager:close(self.histfile_dialog)
FileManagerBookInfo:onShowBookDescription(nil, item.file)
end,
},
})
self.histfile_dialog = ButtonDialogTitle:new{
title = BD.filename(item.text:match("([^/]+)$")),
title_align = "center",
buttons = buttons,
}
2014-03-13 13:52:43 +00:00
UIManager:show(self.histfile_dialog)
return true
end
2013-08-14 09:29:05 +00:00
-- Can't *actually* name it onSetRotationMode, or it also fires in FM itself ;).
function FileManagerHistory:MenuSetRotationModeHandler(rotation)
if rotation ~= nil and rotation ~= Screen:getRotationMode() then
UIManager:close(self._manager.hist_menu)
-- Also re-layout ReaderView or FileManager itself
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:onShowHist()
end
return true
end
function FileManagerHistory:onShowHist()
2014-03-13 13:52:43 +00:00
self.hist_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,
2022-03-12 10:26:11 +00:00
title_bar_left_icon = "appbar.menu",
onLeftButtonTap = function() self:showHistDialog() end,
2014-03-13 13:52:43 +00:00
onMenuHold = self.onMenuHold,
onSetRotationMode = self.MenuSetRotationModeHandler,
2014-03-13 13:52:43 +00:00
_manager = self,
}
self.filter = G_reader_settings:readSetting("history_filter", "all")
if self.filter ~= "all" then
self:fetchStatuses(false)
end
2014-03-13 13:52:43 +00:00
self:updateItemTable()
self.hist_menu.close_callback = function()
if self.files_updated then -- refresh Filemanager list of files
local FileManager = require("apps/filemanager/filemanager")
if FileManager.instance then
FileManager.instance:onRefresh()
end
self.files_updated = nil
end
2022-03-12 10:26:11 +00:00
self.statuses_fetched = nil
UIManager:close(self.hist_menu)
G_reader_settings:saveSetting("history_filter", self.filter)
2014-03-13 13:52:43 +00:00
end
UIManager:show(self.hist_menu)
2014-03-13 13:52:43 +00:00
return true
2013-08-14 09:29:05 +00:00
end
2022-03-12 10:26:11 +00:00
function FileManagerHistory:showHistDialog()
if not self.statuses_fetched then
self:fetchStatuses(true)
2022-03-12 10:26:11 +00:00
end
local hist_dialog
local buttons = {}
local function genFilterButton(filter)
2022-03-12 10:26:11 +00:00
return {
text = T(_("%1 (%2)"), filter_text[filter], self.count[filter]),
2022-03-12 10:26:11 +00:00
callback = function()
UIManager:close(hist_dialog)
self.filter = filter
2022-03-12 10:26:11 +00:00
self:updateItemTable()
end,
}
end
table.insert(buttons, {
genFilterButton("reading"),
genFilterButton("abandoned"),
genFilterButton("complete"),
})
table.insert(buttons, {
genFilterButton("all"),
genFilterButton("new"),
genFilterButton("deleted"),
2022-03-12 10:26:11 +00:00
})
if self.count.deleted > 0 then
table.insert(buttons, {}) -- separator
2022-03-12 10:26:11 +00:00
table.insert(buttons, {
{
text = _("Clear history of deleted files"),
callback = function()
UIManager:show(ConfirmBox:new{
text = _("Clear history of deleted files?"),
ok_text = _("Clear"),
ok_callback = function()
UIManager:close(hist_dialog)
require("readhistory"):clearMissing()
self:updateItemTable()
end,
})
end,
},
2022-03-12 10:26:11 +00:00
})
end
hist_dialog = ButtonDialogTitle:new{
title = _("Filter by book status"),
title_align = "center",
buttons = buttons,
}
UIManager:show(hist_dialog)
end
return FileManagerHistory