mirror of https://github.com/koreader/koreader
[feat] Favorites: organize book into collections (#5527)
View, add, remove, sort, open book to/from collections. For now, only one collection named Favorites.pull/5572/head
parent
04ce1836d8
commit
371e3336a5
@ -0,0 +1,124 @@
|
||||
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
||||
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local ReadCollection = require("readcollection")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = require("device").screen
|
||||
local _ = require("gettext")
|
||||
|
||||
local FileManagerCollection = InputContainer:extend{
|
||||
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)
|
||||
self.collfile_dialog = nil
|
||||
local buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Sort"),
|
||||
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 = _("Remove from collection"),
|
||||
callback = function()
|
||||
ReadCollection:removeItem(item.file, self._manager.coll_menu.collection)
|
||||
self._manager:updateItemTable()
|
||||
UIManager:close(self.collfile_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Book information"),
|
||||
enabled = FileManagerBookInfo:isSupported(item.file),
|
||||
callback = function()
|
||||
FileManagerBookInfo:show(item.file)
|
||||
UIManager:close(self.collfile_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
self.collfile_dialog = ButtonDialogTitle:new{
|
||||
title = item.text:match("([^/]+)$"),
|
||||
title_align = "center",
|
||||
buttons = buttons,
|
||||
}
|
||||
UIManager:show(self.collfile_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
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,
|
||||
_manager = self,
|
||||
collection = collection,
|
||||
}
|
||||
self:updateItemTable()
|
||||
self.coll_menu.close_callback = function()
|
||||
-- Close it at next tick so it stays displayed
|
||||
-- while a book is opening (avoids a transient
|
||||
-- display of the underlying File Browser)
|
||||
UIManager:nextTick(function()
|
||||
UIManager:close(self.coll_menu)
|
||||
end)
|
||||
end
|
||||
UIManager:show(self.coll_menu)
|
||||
return true
|
||||
end
|
||||
|
||||
return FileManagerCollection
|
@ -0,0 +1,159 @@
|
||||
local DataStorage = require("datastorage")
|
||||
local LuaSettings = require("luasettings")
|
||||
local getFriendlySize = require("util").getFriendlySize
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local realpath = require("ffi/util").realpath
|
||||
local util = require("util")
|
||||
|
||||
local DEFAULT_COLLECTION_NAME = "favorites"
|
||||
local collection_file = DataStorage:getSettingsDir() .. "/collection.lua"
|
||||
|
||||
local ReadCollection = {}
|
||||
|
||||
function ReadCollection:read(collection_name)
|
||||
if not collection_name then collection_name = DEFAULT_COLLECTION_NAME end
|
||||
local collections = LuaSettings:open(collection_file)
|
||||
local coll = collections:readSetting(collection_name) or {}
|
||||
local coll_max_item = 0
|
||||
|
||||
for _, v in pairs(coll) do
|
||||
if v.order > coll_max_item then
|
||||
coll_max_item = v.order
|
||||
end
|
||||
end
|
||||
return coll, coll_max_item
|
||||
end
|
||||
|
||||
function ReadCollection:readAllCollection()
|
||||
local collection = LuaSettings:open(collection_file)
|
||||
if collection and collection.data then
|
||||
return collection.data
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function ReadCollection:prepareList(collection_name)
|
||||
local data = self:read(collection_name)
|
||||
local list = {}
|
||||
for _, v in pairs(data) do
|
||||
local file_exists = lfs.attributes(v.file, "mode") == "file"
|
||||
table.insert(list, {
|
||||
order = v.order,
|
||||
text = v.file:gsub(".*/", ""),
|
||||
file = realpath(v.file) or v.file, -- keep orig file path of deleted files
|
||||
dim = not file_exists, -- "dim", as expected by Menu
|
||||
mandatory = file_exists and getFriendlySize(lfs.attributes(v.file, "size") or 0),
|
||||
callback = function()
|
||||
local ReaderUI = require("apps/reader/readerui")
|
||||
ReaderUI:showReader(v.file)
|
||||
end
|
||||
})
|
||||
end
|
||||
table.sort(list, function(v1,v2)
|
||||
return v1.order < v2.order
|
||||
end)
|
||||
return list
|
||||
end
|
||||
|
||||
function ReadCollection:removeItemByPath(path, is_dir)
|
||||
local dir
|
||||
local should_write = false
|
||||
if is_dir then
|
||||
path = path .. "/"
|
||||
end
|
||||
local coll = self:readAllCollection()
|
||||
for i, _ in pairs(coll) do
|
||||
local single_collection = coll[i]
|
||||
for item = #single_collection, 1, -1 do
|
||||
if not is_dir and single_collection[item].file == path then
|
||||
should_write = true
|
||||
table.remove(single_collection, item)
|
||||
elseif is_dir then
|
||||
dir = util.splitFilePathName(single_collection[item].file)
|
||||
if dir == path then
|
||||
should_write = true
|
||||
table.remove(single_collection, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if should_write then
|
||||
local collection = LuaSettings:open(collection_file)
|
||||
collection.data = coll
|
||||
collection:flush()
|
||||
end
|
||||
end
|
||||
|
||||
function ReadCollection:updateItemByPath(old_path, new_path)
|
||||
local is_dir = false
|
||||
local dir, file
|
||||
if lfs.attributes(new_path, "mode") == "directory" then
|
||||
is_dir = true
|
||||
old_path = old_path .. "/"
|
||||
end
|
||||
local should_write = false
|
||||
local coll = self:readAllCollection()
|
||||
for i, j in pairs(coll) do
|
||||
for k, v in pairs(j) do
|
||||
if not is_dir and v.file == old_path then
|
||||
should_write = true
|
||||
coll[i][k].file = new_path
|
||||
elseif is_dir then
|
||||
dir, file = util.splitFilePathName(v.file)
|
||||
if dir == old_path then
|
||||
should_write = true
|
||||
coll[i][k].file = string.format("%s/%s", new_path, file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if should_write then
|
||||
local collection = LuaSettings:open(collection_file)
|
||||
collection.data = coll
|
||||
collection:flush()
|
||||
end
|
||||
end
|
||||
|
||||
function ReadCollection:removeItem(item, collection_name)
|
||||
local coll = self:read(collection_name)
|
||||
for k, v in pairs(coll) do
|
||||
if v.file == item then
|
||||
table.remove(coll, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
self:writeCollection(coll, collection_name)
|
||||
end
|
||||
|
||||
function ReadCollection:writeCollection(coll_items, collection_name)
|
||||
if not collection_name then collection_name = DEFAULT_COLLECTION_NAME end
|
||||
local collection = LuaSettings:open(collection_file)
|
||||
collection:saveSetting(collection_name, coll_items)
|
||||
collection:flush()
|
||||
end
|
||||
|
||||
function ReadCollection:addItem(file, collection_name)
|
||||
local coll, coll_max_item = self:read(collection_name)
|
||||
coll_max_item = coll_max_item + 1
|
||||
local collection_item =
|
||||
{
|
||||
file = file,
|
||||
order = coll_max_item
|
||||
}
|
||||
table.insert(coll, collection_item)
|
||||
self:writeCollection(coll, collection_name)
|
||||
end
|
||||
|
||||
function ReadCollection:checkItemExist(item, collection_name)
|
||||
local coll = self:read(collection_name)
|
||||
for _, v in pairs(coll) do
|
||||
if v.file == item then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return ReadCollection
|
||||
|
Loading…
Reference in New Issue