2016-04-18 22:38:14 +00:00
|
|
|
local DataStorage = require("datastorage")
|
|
|
|
local DocSettings = require("docsettings")
|
2022-11-17 04:53:35 +00:00
|
|
|
local datetime = require("datetime")
|
2016-04-18 22:38:14 +00:00
|
|
|
local dump = require("dump")
|
2019-12-10 22:00:08 +00:00
|
|
|
local ffiutil = require("ffi/util")
|
2020-08-29 16:25:36 +00:00
|
|
|
local util = require("util")
|
2019-12-10 22:00:08 +00:00
|
|
|
local joinPath = ffiutil.joinPath
|
2017-07-19 12:56:17 +00:00
|
|
|
local lfs = require("libs/libkoreader-lfs")
|
2019-12-10 22:00:08 +00:00
|
|
|
local realpath = ffiutil.realpath
|
2016-04-18 22:38:14 +00:00
|
|
|
|
|
|
|
local history_file = joinPath(DataStorage:getDataDir(), "history.lua")
|
|
|
|
|
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 is a singleton
|
2016-04-18 22:38:14 +00:00
|
|
|
local ReadHistory = {
|
|
|
|
hist = {},
|
2017-07-19 12:56:17 +00:00
|
|
|
last_read_time = 0,
|
2016-04-18 22:38:14 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
local function selectCallback(path)
|
|
|
|
local ReaderUI = require("apps/reader/readerui")
|
|
|
|
ReaderUI:showReader(path)
|
|
|
|
end
|
|
|
|
|
2016-04-18 22:38:14 +00:00
|
|
|
local function buildEntry(input_time, input_file)
|
2020-08-29 16:25:36 +00:00
|
|
|
local file_path = realpath(input_file) or input_file -- keep orig file path of deleted files
|
2016-04-18 22:38:14 +00:00
|
|
|
return {
|
|
|
|
time = input_time,
|
2020-08-29 16:25:36 +00:00
|
|
|
file = file_path,
|
2022-10-25 10:15:59 +00:00
|
|
|
text = input_file:gsub(".*/", ""),
|
|
|
|
dim = lfs.attributes(file_path, "mode") ~= "file", -- "dim", as expected by Menu
|
|
|
|
mandatory_func = function() -- Show the last read time
|
2020-08-29 16:25:36 +00:00
|
|
|
local readerui_instance = require("apps/reader/readerui"):_getRunningInstance()
|
2021-05-18 16:20:34 +00:00
|
|
|
local currently_opened_file = readerui_instance and readerui_instance.document and readerui_instance.document.file
|
2020-08-29 16:25:36 +00:00
|
|
|
local last_read_ts
|
|
|
|
if file_path == currently_opened_file then
|
|
|
|
-- Don't use the sidecar file date which is updated regularly while
|
|
|
|
-- reading: keep showing the opening time for the current document.
|
|
|
|
last_read_ts = input_time
|
|
|
|
else
|
|
|
|
-- For past documents, the last save time of the settings is better
|
|
|
|
-- as last read time than input_time (its last opening time, that
|
2022-10-25 10:15:59 +00:00
|
|
|
-- we fallback to if no sidecar file)
|
2020-08-29 16:25:36 +00:00
|
|
|
last_read_ts = DocSettings:getLastSaveTime(file_path) or input_time
|
|
|
|
end
|
2022-11-17 04:53:35 +00:00
|
|
|
return datetime.secondsToDateTime(last_read_ts, G_reader_settings:isTrue("twelve_hour_clock"))
|
2020-08-29 16:25:36 +00:00
|
|
|
end,
|
2021-02-20 18:05:10 +00:00
|
|
|
select_enabled_func = function()
|
|
|
|
return lfs.attributes(file_path, "mode") == "file"
|
|
|
|
end,
|
2016-04-18 22:38:14 +00:00
|
|
|
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
|
|
|
selectCallback(input_file)
|
2022-10-25 10:15:59 +00:00
|
|
|
end,
|
2016-04-18 22:38:14 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
function ReadHistory:getIndexByFile(item_file)
|
|
|
|
for i, v in ipairs(self.hist) do
|
|
|
|
if item_file == v.file then
|
|
|
|
return i
|
|
|
|
end
|
2016-09-13 03:02:48 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Returns leftmost index of the entry with item_time using binary search
|
|
|
|
-- (items in history are sorted by time in reverse order).
|
|
|
|
-- If several entries have equal time, search within them by item_file in alphabetical order.
|
|
|
|
-- If there are no entries with item_time, returns insertion index.
|
|
|
|
function ReadHistory:getIndexByTime(item_time, item_file)
|
|
|
|
local hist_nb = #self.hist
|
|
|
|
if hist_nb == 0 then
|
|
|
|
return 1
|
2016-09-13 03:02:48 +00:00
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
if item_time > self.hist[1].time then
|
|
|
|
return 1
|
|
|
|
elseif item_time < self.hist[hist_nb].time then
|
|
|
|
return hist_nb + 1
|
2016-07-19 05:37:57 +00:00
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
local s, e, m, d = 1, hist_nb
|
|
|
|
while s <= e do
|
|
|
|
m = bit.rshift(s + e, 1)
|
|
|
|
if item_time < self.hist[m].time then
|
|
|
|
s, d = m + 1, 1
|
|
|
|
else
|
|
|
|
e, d = m - 1, 0
|
|
|
|
end
|
2017-02-25 21:16:19 +00:00
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
local index = m + d
|
|
|
|
if item_file then
|
|
|
|
while index <= #self.hist
|
|
|
|
and self.hist[index].time == item_time
|
|
|
|
and self.hist[index].file:gsub(".*/", "") < item_file do
|
|
|
|
index = index + 1
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
return index
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Reduces number of history items to the required limit by removing old items.
|
2016-04-18 22:38:14 +00:00
|
|
|
function ReadHistory:_reduce()
|
2022-10-25 10:15:59 +00:00
|
|
|
local history_size = G_reader_settings:readSetting("history_size") or 500
|
|
|
|
while #self.hist > history_size do
|
|
|
|
table.remove(self.hist)
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Saves history table to a file.
|
2016-04-18 22:38:14 +00:00
|
|
|
function ReadHistory:_flush()
|
|
|
|
local content = {}
|
2020-05-29 12:30:39 +00:00
|
|
|
for _, v in ipairs(self.hist) do
|
|
|
|
table.insert(content, {
|
2016-04-18 22:38:14 +00:00
|
|
|
time = v.time,
|
|
|
|
file = v.file
|
2020-05-29 12:30:39 +00:00
|
|
|
})
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
local f = io.open(history_file, "w")
|
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
|
|
|
if f then
|
|
|
|
f:write("return " .. dump(content) .. "\n")
|
|
|
|
ffiutil.fsyncOpenedFile(f) -- force flush to the storage device
|
|
|
|
f:close()
|
|
|
|
end
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
|
2017-07-19 12:56:17 +00:00
|
|
|
--- Reads history table from file.
|
|
|
|
-- @treturn boolean true if the history_file has been updated and reloaded.
|
2022-02-17 12:17:21 +00:00
|
|
|
function ReadHistory:_read(force_read)
|
2017-07-19 12:56:17 +00:00
|
|
|
local history_file_modification_time = lfs.attributes(history_file, "modification")
|
2022-10-25 10:15:59 +00:00
|
|
|
if history_file_modification_time == nil then -- no history_file, proceed legacy only
|
|
|
|
return true
|
2017-07-19 12:56:17 +00:00
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
if force_read or (history_file_modification_time > self.last_read_time) then
|
|
|
|
self.last_read_time = history_file_modification_time
|
|
|
|
local ok, data = pcall(dofile, history_file)
|
|
|
|
if ok and data then
|
|
|
|
self.hist = {}
|
|
|
|
for _, v in ipairs(data) do
|
|
|
|
table.insert(self.hist, buildEntry(v.time, v.file))
|
|
|
|
end
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
return true
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Reads history from legacy history folder.
|
2016-04-18 22:38:14 +00:00
|
|
|
function ReadHistory:_readLegacyHistory()
|
2022-10-25 10:15:59 +00:00
|
|
|
local history_updated
|
2016-04-18 22:38:14 +00:00
|
|
|
local history_dir = DataStorage:getHistoryDir()
|
|
|
|
for f in lfs.dir(history_dir) do
|
|
|
|
local path = joinPath(history_dir, f)
|
|
|
|
if lfs.attributes(path, "mode") == "file" then
|
2016-07-19 05:37:57 +00:00
|
|
|
path = DocSettings:getPathFromHistory(f)
|
|
|
|
if path ~= nil and path ~= "" then
|
|
|
|
local file = DocSettings:getNameFromHistory(f)
|
|
|
|
if file ~= nil and file ~= "" then
|
2022-10-25 10:15:59 +00:00
|
|
|
local item_path = joinPath(path, file)
|
|
|
|
local item_time = lfs.attributes(joinPath(history_dir, f), "modification")
|
|
|
|
if self:addItem(item_path, item_time, true) then
|
|
|
|
history_updated = true
|
|
|
|
end
|
2016-07-19 05:37:57 +00:00
|
|
|
end
|
|
|
|
end
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
if history_updated then
|
|
|
|
self:_reduce()
|
|
|
|
self:_flush()
|
|
|
|
self:ensureLastFile()
|
|
|
|
end
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function ReadHistory:_init()
|
2017-07-19 12:56:17 +00:00
|
|
|
self:reload()
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
|
2020-05-06 19:11:34 +00:00
|
|
|
function ReadHistory:ensureLastFile()
|
2022-10-25 10:15:59 +00:00
|
|
|
local last_existing_file
|
|
|
|
for _, v in ipairs(self.hist) do
|
|
|
|
if lfs.attributes(v.file, "mode") == "file" then
|
|
|
|
last_existing_file = v.file
|
2020-05-06 19:11:34 +00:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
G_reader_settings:saveSetting("lastfile", last_existing_file)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadHistory:getLastFile()
|
|
|
|
self:ensureLastFile()
|
|
|
|
return G_reader_settings:readSetting("lastfile")
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Get last or previous file in history that is not current_file
|
|
|
|
-- (self.ui.document.file, provided as current_file, might have
|
|
|
|
-- been removed from history).
|
2020-05-06 19:11:34 +00:00
|
|
|
function ReadHistory:getPreviousFile(current_file)
|
|
|
|
if not current_file then
|
|
|
|
current_file = G_reader_settings:readSetting("lastfile")
|
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
for _, v in ipairs(self.hist) do
|
2020-05-06 19:11:34 +00:00
|
|
|
-- skip current document and deleted items kept in history
|
2022-10-25 10:15:59 +00:00
|
|
|
if v.file ~= current_file and lfs.attributes(v.file, "mode") == "file" then
|
|
|
|
return v.file
|
2020-05-06 19:11:34 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Used in the BookShortcuts plugin.
|
2022-03-23 22:05:18 +00:00
|
|
|
function ReadHistory:getFileByDirectory(directory, recursive)
|
2021-11-21 19:51:42 +00:00
|
|
|
local real_path = realpath(directory)
|
2022-10-25 10:15:59 +00:00
|
|
|
for _, v in ipairs(self.hist) do
|
|
|
|
local ipath = realpath(ffiutil.dirname(v.file))
|
2022-03-23 22:05:18 +00:00
|
|
|
if ipath == real_path or (recursive and util.stringStartsWith(ipath, real_path)) then
|
2022-10-25 10:15:59 +00:00
|
|
|
return v.file
|
2021-11-21 19:51:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
function ReadHistory:updateItemByPath(old_path, new_path)
|
|
|
|
local index = self:getIndexByFile(old_path)
|
|
|
|
if index then
|
|
|
|
self.hist[index].file = new_path
|
|
|
|
self.hist[index].text = new_path:gsub(".*/", "")
|
|
|
|
self.hist[index].callback = function()
|
|
|
|
selectCallback(new_path)
|
|
|
|
end
|
|
|
|
self:_flush()
|
|
|
|
self:reload(true)
|
|
|
|
end
|
|
|
|
if G_reader_settings:readSetting("lastfile") == old_path then
|
|
|
|
G_reader_settings:saveSetting("lastfile", new_path)
|
|
|
|
end
|
|
|
|
self:ensureLastFile()
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Updates the history list after deleting a file.
|
2020-05-06 19:11:34 +00:00
|
|
|
function ReadHistory:fileDeleted(path)
|
2022-10-25 10:15:59 +00:00
|
|
|
local index = self:getIndexByFile(path)
|
|
|
|
if index then
|
|
|
|
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
|
|
|
self:removeItem(self.hist[index], index)
|
|
|
|
else
|
|
|
|
self.hist[index].dim = true
|
|
|
|
self:ensureLastFile()
|
2020-05-06 19:11:34 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Removes the history item if the document settings has been reset.
|
2020-05-06 19:11:34 +00:00
|
|
|
function ReadHistory:fileSettingsPurged(path)
|
2021-03-06 21:44:18 +00:00
|
|
|
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
2020-05-06 19:11:34 +00:00
|
|
|
-- Also remove it from history on purge when that setting is enabled
|
|
|
|
self:removeItemByPath(path)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Checks the history list for deleted files and removes history items respectively.
|
2017-02-25 18:22:04 +00:00
|
|
|
function ReadHistory:clearMissing()
|
2022-10-25 10:15:59 +00:00
|
|
|
local history_updated
|
|
|
|
for i, v in ipairs(self.hist) do
|
|
|
|
if v.file == nil or lfs.attributes(v.file, "mode") ~= "file" then
|
|
|
|
self:removeItem(v, i, true) -- no flush
|
|
|
|
history_updated = true
|
2017-02-25 18:22:04 +00:00
|
|
|
end
|
|
|
|
end
|
2022-10-25 10:15:59 +00:00
|
|
|
if history_updated then
|
|
|
|
self:_flush()
|
|
|
|
self:ensureLastFile()
|
2017-02-25 21:16:19 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
function ReadHistory:removeItemByPath(path)
|
|
|
|
local index = self:getIndexByFile(path)
|
|
|
|
if index then
|
|
|
|
self:removeItem(self.hist[index], index)
|
2020-05-06 19:11:34 +00:00
|
|
|
end
|
2018-01-16 17:20:25 +00:00
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
function ReadHistory:removeItem(item, idx, no_flush)
|
|
|
|
local index = idx or self:getIndexByTime(item.time, item.file:gsub(".*/", ""))
|
|
|
|
table.remove(self.hist, index)
|
2016-04-18 22:38:14 +00:00
|
|
|
os.remove(DocSettings:getHistoryPath(item.file))
|
2022-10-25 10:15:59 +00:00
|
|
|
if not no_flush then
|
|
|
|
self:_flush()
|
|
|
|
self:ensureLastFile()
|
|
|
|
end
|
2016-04-18 22:38:14 +00:00
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Adds new item (last opened document) to the top of the history list.
|
|
|
|
-- If item time (ts) is passed, add item to the history list at this time position.
|
|
|
|
function ReadHistory:addItem(file, ts, no_flash)
|
2016-04-18 22:38:14 +00:00
|
|
|
if file ~= nil and lfs.attributes(file, "mode") == "file" then
|
2022-10-25 10:15:59 +00:00
|
|
|
local index = self:getIndexByFile(realpath(file))
|
|
|
|
if ts and index and self.hist[index].time == ts then
|
|
|
|
return -- this legacy item is in the history already
|
|
|
|
end
|
2020-12-15 20:10:36 +00:00
|
|
|
local now = ts or os.time()
|
2018-05-30 04:50:15 +00:00
|
|
|
local mtime = lfs.attributes(file, "modification")
|
|
|
|
lfs.touch(file, now, mtime)
|
2022-10-25 10:15:59 +00:00
|
|
|
if index == 1 and not ts then -- last book
|
|
|
|
self.hist[1].time = now
|
|
|
|
else -- old or new book
|
|
|
|
if index then -- old book
|
|
|
|
table.remove(self.hist, index)
|
|
|
|
end
|
|
|
|
index = ts and self:getIndexByTime(ts, file:gsub(".*/", "")) or 1
|
|
|
|
table.insert(self.hist, index, buildEntry(now, file))
|
|
|
|
end
|
|
|
|
if not no_flash then
|
|
|
|
self:_reduce()
|
|
|
|
self:_flush()
|
|
|
|
self:ensureLastFile()
|
|
|
|
end
|
|
|
|
return true -- used while adding legacy items
|
2017-09-22 16:24:38 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-25 10:15:59 +00:00
|
|
|
--- Reloads history from history_file and legacy history folder.
|
2022-02-17 12:17:21 +00:00
|
|
|
function ReadHistory:reload(force_read)
|
|
|
|
if self:_read(force_read) then
|
2017-07-19 12:56:17 +00:00
|
|
|
self:_readLegacyHistory()
|
2022-10-25 10:15:59 +00:00
|
|
|
if G_reader_settings:isTrue("autoremove_deleted_items_from_history") then
|
|
|
|
self:clearMissing()
|
|
|
|
end
|
2017-07-19 12:56:17 +00:00
|
|
|
self:_reduce()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-18 22:38:14 +00:00
|
|
|
ReadHistory:_init()
|
|
|
|
|
|
|
|
return ReadHistory
|