mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
File browser: sort by metadata (#13437)
This commit is contained in:
@@ -138,6 +138,7 @@ function FileManager:setupLayout()
|
||||
}
|
||||
|
||||
local file_chooser = FileChooser:new{
|
||||
name = "filemanager",
|
||||
path = self.root_path,
|
||||
focused_path = self.focused_file,
|
||||
show_parent = self.show_parent,
|
||||
@@ -146,7 +147,7 @@ function FileManager:setupLayout()
|
||||
-- allow left bottom tap gesture, otherwise it is eaten by hidden return button
|
||||
return_arrow_propagation = true,
|
||||
-- allow Menu widget to delegate handling of some gestures to GestureManager
|
||||
filemanager = self,
|
||||
ui = self,
|
||||
-- Tell FileChooser (i.e., Menu) to use our own title bar instead of Menu's default one
|
||||
custom_title_bar = self.title_bar,
|
||||
search_callback = function(search_string)
|
||||
@@ -344,10 +345,6 @@ function FileManager:setupLayout()
|
||||
|
||||
self[1] = fm_ui
|
||||
|
||||
self.menu = FileManagerMenu:new{
|
||||
ui = self
|
||||
}
|
||||
|
||||
-- No need to reinvent the wheel, use FileChooser's layout
|
||||
self.layout = file_chooser.layout
|
||||
|
||||
@@ -390,15 +387,13 @@ end
|
||||
|
||||
-- NOTE: The only thing that will *ever* instantiate a new FileManager object is our very own showFiles below!
|
||||
function FileManager:init()
|
||||
self:setupLayout()
|
||||
self.active_widgets = {}
|
||||
|
||||
self:registerModule("screenshot", Screenshoter:new{
|
||||
prefix = "FileManager",
|
||||
ui = self,
|
||||
}, true)
|
||||
|
||||
self:registerModule("menu", self.menu)
|
||||
self:registerModule("menu", FileManagerMenu:new{ ui = self })
|
||||
self:registerModule("history", FileManagerHistory:new{ ui = self })
|
||||
self:registerModule("bookinfo", FileManagerBookInfo:new{ ui = self })
|
||||
self:registerModule("collections", FileManagerCollection:new{ ui = self })
|
||||
@@ -425,6 +420,7 @@ function FileManager:init()
|
||||
end
|
||||
end
|
||||
|
||||
self:setupLayout()
|
||||
self:initGesListener()
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
self:handleEvent(Event:new("PathChanged", self.file_chooser.path))
|
||||
|
||||
@@ -284,7 +284,7 @@ function BookInfo:getDocProps(file, book_props, no_open_document)
|
||||
|
||||
-- If still no book_props, open the document to get them
|
||||
if not book_props and not no_open_document then
|
||||
local document = DocumentRegistry:openDocument(file)
|
||||
local document = DocumentRegistry:hasProvider(file) and DocumentRegistry:openDocument(file)
|
||||
if document then
|
||||
local loaded = true
|
||||
local pages
|
||||
|
||||
@@ -49,13 +49,6 @@ function FileManagerCollection:addToMainMenu(menu_items)
|
||||
}
|
||||
end
|
||||
|
||||
function FileManagerCollection:getDocProps(file)
|
||||
if self.doc_props_cache[file] == nil then
|
||||
self.doc_props_cache[file] = self.ui.bookinfo:getDocProps(file, nil, true) -- do not open the document
|
||||
end
|
||||
return self.doc_props_cache[file]
|
||||
end
|
||||
|
||||
-- collection
|
||||
|
||||
function FileManagerCollection:getCollectionTitle(collection_name)
|
||||
@@ -122,7 +115,7 @@ function FileManagerCollection:updateItemTable(item_table, focused_file)
|
||||
mandatory = self.mandatory_func and self.mandatory_func(item) or util.getFriendlySize(item.attr.size or 0),
|
||||
}
|
||||
if self.item_func then
|
||||
self.item_func(item_tmp, self:getDocProps(item_tmp.file))
|
||||
self.item_func(item_tmp, self.ui)
|
||||
end
|
||||
table.insert(item_table, item_tmp)
|
||||
end
|
||||
@@ -143,7 +136,7 @@ function FileManagerCollection:isItemMatch(item)
|
||||
end
|
||||
end
|
||||
if self.match_table.props then
|
||||
local doc_props = self:getDocProps(item.file)
|
||||
local doc_props = self.ui.bookinfo:getDocProps(item.file, nil, true)
|
||||
for prop, value in pairs(self.match_table.props) do
|
||||
if (doc_props[prop] or self.empty_prop) ~= value then
|
||||
return false
|
||||
@@ -317,7 +310,7 @@ function FileManagerCollection:showCollDialog()
|
||||
UIManager:close(coll_dialog)
|
||||
local prop_values = {}
|
||||
for idx, item in ipairs(self.booklist_menu.item_table) do
|
||||
local doc_prop = self:getDocProps(item.file)[button_prop]
|
||||
local doc_prop = self.ui.bookinfo:getDocProps(item.file, nil, true)[button_prop]
|
||||
if doc_prop == nil then
|
||||
doc_prop = { self.empty_prop }
|
||||
elseif button_prop == "series" then
|
||||
@@ -496,7 +489,7 @@ function FileManagerCollection:setCollate(collate_id, collate_reverse)
|
||||
coll_settings.collate_reverse = collate_reverse or nil
|
||||
end
|
||||
if collate_id then
|
||||
local collate = BookList.metadata_collates[collate_id] or BookList.collates[collate_id]
|
||||
local collate = BookList.collates[collate_id]
|
||||
self.item_func = collate.item_func
|
||||
self.mandatory_func = collate.mandatory_func
|
||||
self.sorting_func, self.sort_cache = collate.init_sort_func(self.sort_cache)
|
||||
@@ -517,7 +510,7 @@ function FileManagerCollection:showArrangeBooksDialog()
|
||||
local curr_collate_id = coll_settings.collate
|
||||
local arrange_dialog
|
||||
local function genCollateButton(collate_id)
|
||||
local collate = BookList.metadata_collates[collate_id] or BookList.collates[collate_id]
|
||||
local collate = BookList.collates[collate_id]
|
||||
return {
|
||||
text = collate.text .. (curr_collate_id == collate_id and " ✓" or ""),
|
||||
callback = function()
|
||||
@@ -1135,7 +1128,7 @@ function FileManagerCollection:searchCollections(coll_name)
|
||||
if not DocumentRegistry:hasProvider(file) then
|
||||
return false
|
||||
end
|
||||
local book_props = self:getDocProps(file)
|
||||
local book_props = self.ui.bookinfo:getDocProps(file, nil, true)
|
||||
if next(book_props) ~= nil and self.ui.bookinfo:findInProps(book_props, self.search_str, self.case_sensitive) then
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -151,17 +151,17 @@ function FileSearcher:doSearch()
|
||||
FileSearcher.search_hash = search_hash
|
||||
self.no_metadata_count = no_metadata_count
|
||||
-- Cannot do this in getList() within Trapper (cannot serialize function)
|
||||
local collate = FileChooser:getCollate()
|
||||
local fc = self.ui.file_chooser or FileChooser:new{ ui = self.ui }
|
||||
local collate = fc:getCollate()
|
||||
for i, v in ipairs(dirs) do
|
||||
local f, fullpath, attributes = unpack(v)
|
||||
dirs[i] = FileChooser:getListItem(nil, f, fullpath, attributes, collate)
|
||||
dirs[i] = fc:getListItem(nil, f, fullpath, attributes, collate)
|
||||
end
|
||||
for i, v in ipairs(files) do
|
||||
local f, fullpath, attributes = unpack(v)
|
||||
files[i] = FileChooser:getListItem(nil, f, fullpath, attributes, collate)
|
||||
files[i] = fc:getListItem(nil, f, fullpath, attributes, collate)
|
||||
end
|
||||
-- If we have a FileChooser instance, use it, to be able to make use of its natsort cache
|
||||
FileSearcher.search_results = (self.ui.file_chooser or FileChooser):genItemTable(dirs, files)
|
||||
FileSearcher.search_results = fc:genItemTable(dirs, files)
|
||||
end
|
||||
if #FileSearcher.search_results > 0 then
|
||||
self:onShowSearchResults(not_cached)
|
||||
|
||||
@@ -205,12 +205,14 @@ function FileManagerMenu:setUpdateItemTable()
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Item font size: %1"), FileChooser.font_size)
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local current_value = FileChooser.font_size
|
||||
local default_value = FileChooser.getItemFontSize(G_reader_settings:readSetting("items_per_page")
|
||||
or FileChooser.items_per_page_default)
|
||||
return T(_("Item font size: %1"), FileChooser.font_size or default_value)
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local default_value = FileChooser.getItemFontSize(G_reader_settings:readSetting("items_per_page")
|
||||
or FileChooser.items_per_page_default)
|
||||
local current_value = FileChooser.font_size or default_value
|
||||
local widget = SpinWidget:new{
|
||||
title_text = _("Item font size"),
|
||||
value = current_value,
|
||||
@@ -883,7 +885,9 @@ dbg:guard(FileManagerMenu, 'setUpdateItemTable',
|
||||
end)
|
||||
|
||||
function FileManagerMenu:getSortingMenuTable()
|
||||
local sub_item_table = {}
|
||||
local sub_item_table = {
|
||||
max_per_page = 9, -- metadata collates in page 2
|
||||
}
|
||||
for k, v in pairs(self.ui.file_chooser.collates) do
|
||||
table.insert(sub_item_table, {
|
||||
text = v.text,
|
||||
@@ -893,9 +897,7 @@ function FileManagerMenu:getSortingMenuTable()
|
||||
return k == id
|
||||
end,
|
||||
callback = function()
|
||||
G_reader_settings:saveSetting("collate", k)
|
||||
self.ui.file_chooser:clearSortingCache()
|
||||
self.ui.file_chooser:refreshPath()
|
||||
self.ui:onSetSortBy(k)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
@@ -13,231 +13,241 @@ local BookList = Menu:extend{
|
||||
is_borderless = true,
|
||||
is_popout = false,
|
||||
book_info_cache = {}, -- cache in the base class
|
||||
metadata_collates = {
|
||||
title = {
|
||||
text = _("Title"),
|
||||
item_func = function(item, doc_props)
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
}
|
||||
|
||||
BookList.collates = {
|
||||
strcoll = {
|
||||
text = _("name"),
|
||||
menu_order = 10,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
},
|
||||
natural = {
|
||||
text = _("name (natural sorting)"),
|
||||
menu_order = 20,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function(cache)
|
||||
local natsort
|
||||
natsort, cache = sort.natsort_cmp(cache)
|
||||
return function(a, b)
|
||||
return natsort(a.text, b.text)
|
||||
end, cache
|
||||
end,
|
||||
},
|
||||
access = {
|
||||
text = _("last read date"),
|
||||
menu_order = 30,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.access > b.attr.access
|
||||
end
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return datetime.secondsToDateTime(item.attr.access)
|
||||
end,
|
||||
},
|
||||
date = {
|
||||
text = _("date modified"),
|
||||
menu_order = 40,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.modification > b.attr.modification
|
||||
end
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return datetime.secondsToDateTime(item.attr.modification)
|
||||
end,
|
||||
},
|
||||
size = {
|
||||
text = _("size"),
|
||||
menu_order = 50,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.size < b.attr.size
|
||||
end
|
||||
end,
|
||||
},
|
||||
type = {
|
||||
text = _("type"),
|
||||
menu_order = 60,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if (a.suffix or b.suffix) and a.suffix ~= b.suffix then
|
||||
return ffiUtil.strcoll(a.suffix, b.suffix)
|
||||
end
|
||||
end,
|
||||
},
|
||||
authors = {
|
||||
text = _("Authors"),
|
||||
item_func = function(item, doc_props)
|
||||
doc_props.authors = doc_props.authors or "\u{FFFF}" -- sorted last
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.doc_props.authors ~= b.doc_props.authors then
|
||||
return ffiUtil.strcoll(a.doc_props.authors, b.doc_props.authors)
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
item_func = function(item)
|
||||
item.suffix = util.getFileNameSuffix(item.text)
|
||||
end,
|
||||
},
|
||||
percent_unopened_first = {
|
||||
text = _("percent - unopened first"),
|
||||
menu_order = 70,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.opened == b.opened then
|
||||
if a.opened then
|
||||
return a.percent_finished < b.percent_finished
|
||||
end
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
},
|
||||
series = {
|
||||
text = _("Series"),
|
||||
item_func = function(item, doc_props)
|
||||
doc_props.series = doc_props.series or "\u{FFFF}"
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.doc_props.series ~= b.doc_props.series then
|
||||
return ffiUtil.strcoll(a.doc_props.series, b.doc_props.series)
|
||||
return b.opened
|
||||
end
|
||||
end,
|
||||
item_func = function(item)
|
||||
local book_info = BookList.getBookInfo(item.path)
|
||||
item.opened = book_info.been_opened
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.percent_finished = util.round_decimal(book_info.percent_finished or 0, 2)
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
percent_unopened_last = {
|
||||
text = _("percent - unopened last"),
|
||||
menu_order = 80,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.opened == b.opened then
|
||||
if a.opened then
|
||||
return a.percent_finished < b.percent_finished
|
||||
end
|
||||
if a.doc_props.series_index and b.doc_props.series_index then
|
||||
return a.doc_props.series_index < b.doc_props.series_index
|
||||
end
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
},
|
||||
keywords = {
|
||||
text = _("Keywords"),
|
||||
item_func = function(item, doc_props)
|
||||
doc_props.keywords = doc_props.keywords or "\u{FFFF}"
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.opened
|
||||
end
|
||||
end,
|
||||
item_func = function(item)
|
||||
local book_info = BookList.getBookInfo(item.path)
|
||||
item.opened = book_info.been_opened
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.percent_finished = util.round_decimal(book_info.percent_finished or 0, 2)
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
percent_natural = {
|
||||
-- sort 90% > 50% > 0% > on hold > unopened > 100% or finished
|
||||
text = _("percent – unopened – finished last"),
|
||||
menu_order = 90,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function(cache)
|
||||
local natsort
|
||||
natsort, cache = sort.natsort_cmp(cache)
|
||||
local sortfunc = function(a, b)
|
||||
if a.sort_percent == b.sort_percent then
|
||||
return natsort(a.text, b.text)
|
||||
elseif a.sort_percent == 1 then
|
||||
return false
|
||||
elseif b.sort_percent == 1 then
|
||||
return true
|
||||
else
|
||||
return a.sort_percent > b.sort_percent
|
||||
end
|
||||
end
|
||||
return sortfunc, cache
|
||||
end,
|
||||
item_func = function(item)
|
||||
local book_info = BookList.getBookInfo(item.path)
|
||||
item.opened = book_info.been_opened
|
||||
local percent_finished = book_info.percent_finished
|
||||
local sort_percent
|
||||
if item.opened then
|
||||
-- books marked as "finished" or "on hold" should be considered the same as 100% and less than 0% respectively
|
||||
if book_info.status == "complete" then
|
||||
sort_percent = 1.0
|
||||
elseif book_info.status == "abandoned" then
|
||||
sort_percent = -0.01
|
||||
end
|
||||
end
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.sort_percent = sort_percent or util.round_decimal(percent_finished or -1, 2)
|
||||
item.percent_finished = percent_finished or 0
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
title = {
|
||||
text = _("Title"),
|
||||
menu_order = 100,
|
||||
item_func = function(item, ui)
|
||||
local doc_props = ui.bookinfo:getDocProps(item.path or item.file)
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
end
|
||||
end,
|
||||
},
|
||||
authors = {
|
||||
text = _("Authors"),
|
||||
menu_order = 110,
|
||||
item_func = function(item, ui)
|
||||
local doc_props = ui.bookinfo:getDocProps(item.path or item.file)
|
||||
doc_props.authors = doc_props.authors or "\u{FFFF}" -- sorted last
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.doc_props.authors ~= b.doc_props.authors then
|
||||
return ffiUtil.strcoll(a.doc_props.authors, b.doc_props.authors)
|
||||
end
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
end
|
||||
end,
|
||||
},
|
||||
series = {
|
||||
text = _("Series"),
|
||||
menu_order = 120,
|
||||
item_func = function(item, ui)
|
||||
local doc_props = ui.bookinfo:getDocProps(item.path or item.file)
|
||||
doc_props.series = doc_props.series or "\u{FFFF}"
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.doc_props.series ~= b.doc_props.series then
|
||||
return ffiUtil.strcoll(a.doc_props.series, b.doc_props.series)
|
||||
end
|
||||
if a.doc_props.series_index and b.doc_props.series_index then
|
||||
return a.doc_props.series_index < b.doc_props.series_index
|
||||
end
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
end
|
||||
end,
|
||||
},
|
||||
keywords = {
|
||||
text = _("Keywords"),
|
||||
menu_order = 130,
|
||||
item_func = function(item, ui)
|
||||
local doc_props = ui.bookinfo:getDocProps(item.path or item.file)
|
||||
doc_props.keywords = doc_props.keywords or "\u{FFFF}"
|
||||
item.doc_props = doc_props
|
||||
end,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.doc_props.keywords ~= b.doc_props.keywords then
|
||||
return ffiUtil.strcoll(a.doc_props.keywords, b.doc_props.keywords)
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
collates = {
|
||||
strcoll = {
|
||||
text = _("name"),
|
||||
menu_order = 10,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
},
|
||||
natural = {
|
||||
text = _("name (natural sorting)"),
|
||||
menu_order = 20,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function(cache)
|
||||
local natsort
|
||||
natsort, cache = sort.natsort_cmp(cache)
|
||||
return function(a, b)
|
||||
return natsort(a.text, b.text)
|
||||
end, cache
|
||||
end,
|
||||
},
|
||||
access = {
|
||||
text = _("last read date"),
|
||||
menu_order = 30,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.access > b.attr.access
|
||||
end
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return datetime.secondsToDateTime(item.attr.access)
|
||||
end,
|
||||
},
|
||||
date = {
|
||||
text = _("date modified"),
|
||||
menu_order = 40,
|
||||
can_collate_mixed = true,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.modification > b.attr.modification
|
||||
end
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return datetime.secondsToDateTime(item.attr.modification)
|
||||
end,
|
||||
},
|
||||
size = {
|
||||
text = _("size"),
|
||||
menu_order = 50,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
return a.attr.size < b.attr.size
|
||||
end
|
||||
end,
|
||||
},
|
||||
type = {
|
||||
text = _("type"),
|
||||
menu_order = 60,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if (a.suffix or b.suffix) and a.suffix ~= b.suffix then
|
||||
return ffiUtil.strcoll(a.suffix, b.suffix)
|
||||
end
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
end,
|
||||
item_func = function(item)
|
||||
item.suffix = util.getFileNameSuffix(item.text)
|
||||
end,
|
||||
},
|
||||
percent_unopened_first = {
|
||||
text = _("percent - unopened first"),
|
||||
bookinfo_required = true,
|
||||
menu_order = 70,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.opened == b.opened then
|
||||
if a.opened then
|
||||
return a.percent_finished < b.percent_finished
|
||||
end
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
return b.opened
|
||||
end
|
||||
end,
|
||||
item_func = function(item, book_info)
|
||||
item.opened = book_info.been_opened
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.percent_finished = util.round_decimal(book_info.percent_finished or 0, 2)
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
percent_unopened_last = {
|
||||
text = _("percent - unopened last"),
|
||||
bookinfo_required = true,
|
||||
menu_order = 80,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function()
|
||||
return function(a, b)
|
||||
if a.opened == b.opened then
|
||||
if a.opened then
|
||||
return a.percent_finished < b.percent_finished
|
||||
end
|
||||
return ffiUtil.strcoll(a.text, b.text)
|
||||
end
|
||||
return a.opened
|
||||
end
|
||||
end,
|
||||
item_func = function(item, book_info)
|
||||
item.opened = book_info.been_opened
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.percent_finished = util.round_decimal(book_info.percent_finished or 0, 2)
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
percent_natural = {
|
||||
-- sort 90% > 50% > 0% > on hold > unopened > 100% or finished
|
||||
text = _("percent – unopened – finished last"),
|
||||
bookinfo_required = true,
|
||||
menu_order = 90,
|
||||
can_collate_mixed = false,
|
||||
init_sort_func = function(cache)
|
||||
local natsort
|
||||
natsort, cache = sort.natsort_cmp(cache)
|
||||
local sortfunc = function(a, b)
|
||||
if a.sort_percent == b.sort_percent then
|
||||
return natsort(a.text, b.text)
|
||||
elseif a.sort_percent == 1 then
|
||||
return false
|
||||
elseif b.sort_percent == 1 then
|
||||
return true
|
||||
else
|
||||
return a.sort_percent > b.sort_percent
|
||||
end
|
||||
end
|
||||
return sortfunc, cache
|
||||
end,
|
||||
item_func = function(item, book_info)
|
||||
item.opened = book_info.been_opened
|
||||
local percent_finished = book_info.percent_finished
|
||||
local sort_percent
|
||||
if item.opened then
|
||||
-- books marked as "finished" or "on hold" should be considered the same as 100% and less than 0% respectively
|
||||
if book_info.status == "complete" then
|
||||
sort_percent = 1.0
|
||||
elseif book_info.status == "abandoned" then
|
||||
sort_percent = -0.01
|
||||
end
|
||||
end
|
||||
-- smooth 2 decimal points (0.00) instead of 16 decimal points
|
||||
item.sort_percent = sort_percent or util.round_decimal(percent_finished or -1, 2)
|
||||
item.percent_finished = percent_finished or 0
|
||||
end,
|
||||
mandatory_func = function(item)
|
||||
return item.opened and string.format("%d\u{202F}%%", 100 * item.percent_finished) or "–"
|
||||
end,
|
||||
},
|
||||
return ffiUtil.strcoll(a.doc_props.display_title, b.doc_props.display_title)
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -164,8 +164,7 @@ function FileChooser:getListItem(dirpath, f, fullpath, attributes, collate)
|
||||
item.bidi_wrap_func = BD.filename
|
||||
item.is_file = true
|
||||
if collate.item_func ~= nil then
|
||||
local book_info = collate.bookinfo_required and BookList.getBookInfo(item.path)
|
||||
collate.item_func(item, book_info)
|
||||
collate.item_func(item, self.ui)
|
||||
end
|
||||
if show_file_in_bold ~= false then
|
||||
if item.opened == nil then -- could be set in item_func
|
||||
@@ -176,8 +175,7 @@ function FileChooser:getListItem(dirpath, f, fullpath, attributes, collate)
|
||||
item.bold = not item.bold
|
||||
end
|
||||
end
|
||||
item.dim = self.filemanager and self.filemanager.selected_files
|
||||
and self.filemanager.selected_files[item.path]
|
||||
item.dim = self.ui and self.ui.selected_files and self.ui.selected_files[item.path]
|
||||
item.mandatory = self:getMenuItemMandatory(item, collate)
|
||||
else -- folder
|
||||
if item.text == "./." then -- added as content of an unreadable directory
|
||||
@@ -186,7 +184,7 @@ function FileChooser:getListItem(dirpath, f, fullpath, attributes, collate)
|
||||
item.text = item.text.."/"
|
||||
item.bidi_wrap_func = BD.directory
|
||||
item.is_file = false
|
||||
if collate.can_collate_mixed and collate.item_func ~= nil then
|
||||
if collate.can_collate_mixed and collate.item_func ~= nil then -- used by user plugin/patch, don't remove
|
||||
collate.item_func(item)
|
||||
end
|
||||
if dirpath then -- file browser or PathChooser
|
||||
@@ -328,7 +326,7 @@ function FileChooser:refreshPath()
|
||||
self.prev_focused_path = self.focused_path
|
||||
self.focused_path = nil
|
||||
end
|
||||
local subtitle = self.filemanager == nil and BD.directory(filemanagerutil.abbreviate(self.path))
|
||||
local subtitle = self.name ~= "filemanager" and BD.directory(filemanagerutil.abbreviate(self.path)) -- PathChooser
|
||||
self:switchItemTable(nil, self:genItemTableFromPath(self.path), self.path_items[self.path], itemmatch, subtitle)
|
||||
end
|
||||
|
||||
@@ -354,8 +352,8 @@ function FileChooser:changeToPath(path, focused_path)
|
||||
end
|
||||
|
||||
self:refreshPath()
|
||||
if self.filemanager then
|
||||
self.filemanager:handleEvent(Event:new("PathChanged", path))
|
||||
if self.name == "filemanager" then
|
||||
self.ui:handleEvent(Event:new("PathChanged", path))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -464,7 +462,7 @@ function FileChooser:selectAllFilesInFolder(do_select)
|
||||
for _, item in ipairs(self.item_table) do
|
||||
if item.is_file then
|
||||
if do_select then
|
||||
self.filemanager.selected_files[item.path] = true
|
||||
self.ui.selected_files[item.path] = true
|
||||
item.dim = true
|
||||
else
|
||||
item.dim = nil
|
||||
|
||||
@@ -920,7 +920,7 @@ function Menu:init()
|
||||
}
|
||||
end
|
||||
-- delegate swipe gesture to GestureManager in filemanager
|
||||
if not self.filemanager then
|
||||
if self.name ~= "filemanager" then
|
||||
self.ges_events.Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
|
||||
@@ -22,6 +22,11 @@ local PathChooser = FileChooser:extend{
|
||||
}
|
||||
|
||||
function PathChooser:init()
|
||||
local collate = G_reader_settings:readSetting("collate")
|
||||
if self.show_files and (collate == "title" or collate == "authors" or collate == "series" or collate == "keywords") then
|
||||
self.ui = require("apps/reader/readerui").instance or require("apps/filemanager/filemanager").instance
|
||||
end
|
||||
|
||||
if self.title == true then -- default title depending on options
|
||||
if self.select_directory and not self.select_file then
|
||||
self.title = _("Long-press folder's name to choose it")
|
||||
|
||||
@@ -74,7 +74,7 @@ local CoverBrowser = WidgetContainer:extend{
|
||||
}
|
||||
|
||||
function CoverBrowser:init()
|
||||
if self.ui.file_chooser then -- FileManager menu only
|
||||
if not self.ui.document then -- FileManager menu only
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
@@ -675,13 +675,6 @@ function CoverBrowser:setupFileManagerDisplayMode(display_mode)
|
||||
|
||||
if init_done then
|
||||
self:refreshFileManagerInstance()
|
||||
else
|
||||
-- If KOReader has started directly to FileManager, the FileManager
|
||||
-- instance is being init()'ed and there is no FileManager.instance yet,
|
||||
-- but there'll be one at next tick.
|
||||
UIManager:nextTick(function()
|
||||
self:refreshFileManagerInstance()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ function OPDS:onDispatcherRegisterActions()
|
||||
end
|
||||
|
||||
function OPDS:addToMainMenu(menu_items)
|
||||
if self.ui.file_chooser then
|
||||
if not self.ui.document then -- FileManager menu only
|
||||
menu_items.opds = {
|
||||
text = _("OPDS catalog"),
|
||||
callback = function()
|
||||
|
||||
Reference in New Issue
Block a user