mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
@@ -155,6 +155,20 @@ function FileManager:init()
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
end
|
||||
|
||||
function FileManager:resetDimen(dimen)
|
||||
self.dimen = dimen
|
||||
-- backup the root path and path items
|
||||
self.root_path = self.file_chooser.path
|
||||
local path_items_backup = {}
|
||||
for k, v in pairs(self.file_chooser.path_items) do
|
||||
path_items_backup[k] = v
|
||||
end
|
||||
-- reinit filemanager
|
||||
self:init()
|
||||
self.file_chooser.path_items = path_items_backup
|
||||
self:onRefresh()
|
||||
end
|
||||
|
||||
function FileManager:toggleHiddenFiles()
|
||||
self.file_chooser:toggleHiddenFiles()
|
||||
G_reader_settings:saveSetting("show_hidden", self.file_chooser.show_hidden)
|
||||
@@ -172,6 +186,7 @@ end
|
||||
|
||||
function FileManager:onClose()
|
||||
DEBUG("close filemanager")
|
||||
G_reader_settings:saveSetting("fm_screen_mode", Screen:getScreenMode())
|
||||
UIManager:close(self)
|
||||
if self.onExit then
|
||||
self:onExit()
|
||||
@@ -198,7 +213,9 @@ end
|
||||
|
||||
function FileManager:restoreScreenMode()
|
||||
local screen_mode = G_reader_settings:readSetting("fm_screen_mode")
|
||||
Screen:setScreenMode(screen_mode or "portrait")
|
||||
if Screen:getScreenMode() ~= screen_mode then
|
||||
Screen:setScreenMode(screen_mode or "portrait")
|
||||
end
|
||||
UIManager:setDirty(self, "full")
|
||||
end
|
||||
|
||||
@@ -206,15 +223,16 @@ function FileManager:showFiles(path)
|
||||
DEBUG("show home page")
|
||||
path = path or G_reader_settings:readSetting("lastdir") or self:getDefaultDir()
|
||||
G_reader_settings:saveSetting("lastdir", path)
|
||||
UIManager:show(FileManager:new{
|
||||
self:restoreScreenMode()
|
||||
local file_manager = FileManager:new{
|
||||
dimen = Screen:getSize(),
|
||||
root_path = path,
|
||||
onExit = function()
|
||||
self.is_running = false
|
||||
UIManager:quit()
|
||||
self.instance = nil
|
||||
end
|
||||
})
|
||||
self.is_running = true
|
||||
}
|
||||
UIManager:show(file_manager)
|
||||
self.instance = file_manager
|
||||
end
|
||||
|
||||
function FileManager:copyFile(file)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local Device = require("device")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
@@ -204,6 +205,26 @@ function ReaderBookmark:onShowBookmark()
|
||||
bookmark:gotoBookmark(item.page)
|
||||
end
|
||||
|
||||
function bm_menu:onMenuHold(item)
|
||||
self.remove_bookmark_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Remove this bookmark"),
|
||||
callback = function()
|
||||
bookmark:removeBookmark(item)
|
||||
bm_menu:swithItemTable(nil, bookmark.bookmarks, -1)
|
||||
UIManager:close(self.remove_bookmark_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
UIManager:show(self.remove_bookmark_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
bm_menu.close_callback = function()
|
||||
UIManager:close(self.bookmark_menu)
|
||||
end
|
||||
@@ -241,12 +262,32 @@ function ReaderBookmark:getDogearBookmarkIndex(pn_or_xp)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderBookmark:isBookmarkSame(item1, item2)
|
||||
if item1.notes ~= item2.notes then return end
|
||||
if self.ui.document.info.has_pages then
|
||||
if not item2.pos0 or not item2.pos1 then return end
|
||||
local zoom1 = item1.pos0.zoom
|
||||
local zoom1 = item2.pos0.zoom
|
||||
return item2.pos0 and item2.pos1 and item1.pos0.page == item2.pos0.page
|
||||
and item1.pos0.x == item2.pos0.x and item1.pos0.y == item2.pos0.y
|
||||
and item1.pos1.x == item2.pos1.x and item1.pos1.y == item2.pos1.y
|
||||
else
|
||||
return item1.page == item2.page
|
||||
and item1.pos0 == item2.pos0 and item1.pos1 == item2.pos1
|
||||
end
|
||||
end
|
||||
|
||||
-- binary insert of sorted bookmarks
|
||||
function ReaderBookmark:addBookmark(item)
|
||||
local _start, _middle, _end, direction = 1, 1, #self.bookmarks, 0
|
||||
while _start <= _end do
|
||||
local v = self.bookmarks[_middle]
|
||||
_middle = math.floor((_start + _end)/2)
|
||||
-- won't add duplicated bookmarks
|
||||
if self:isBookmarkSame(item, self.bookmarks[_middle]) then
|
||||
DEBUG("skip adding duplicated bookmark")
|
||||
return
|
||||
end
|
||||
if self:isBookmarkInPageOrder(item, self.bookmarks[_middle]) then
|
||||
_end, direction = _middle - 1, 0
|
||||
else
|
||||
|
||||
@@ -59,9 +59,7 @@ end
|
||||
function ReaderDictionary:stardictLookup(word, box)
|
||||
DEBUG("lookup word:", word, box)
|
||||
if word then
|
||||
-- strip ASCII punctuation characters around selected word
|
||||
-- and strip any generic punctuation (U+2000 - U+206F) in the word
|
||||
word = word:gsub("\226[\128-\131][\128-\191]",''):gsub("^%p+",''):gsub("%p+$",'')
|
||||
word = require("util").stripePunctuations(word)
|
||||
DEBUG("stripped word:", word)
|
||||
-- escape quotes and other funny characters in word
|
||||
local std_out = io.popen("./sdcv --utf8-input --utf8-output -nj "..("%q"):format(word), "r")
|
||||
|
||||
@@ -392,7 +392,8 @@ end
|
||||
function ReaderHighlight:saveHighlight()
|
||||
DEBUG("save highlight")
|
||||
local page = self.hold_pos.page
|
||||
if self.hold_pos and self.selected_text then
|
||||
if self.hold_pos and self.selected_text and self.selected_text.pos0
|
||||
and self.selected_text.pos1 then
|
||||
if not self.view.highlight.saved[page] then
|
||||
self.view.highlight.saved[page] = {}
|
||||
end
|
||||
@@ -408,6 +409,8 @@ function ReaderHighlight:saveHighlight()
|
||||
table.insert(self.view.highlight.saved[page], hl_item)
|
||||
self.ui.bookmark:addBookmark({
|
||||
page = self.ui.document.info.has_pages and page or self.selected_text.pos0,
|
||||
pos0 = self.selected_text.pos0,
|
||||
pos1 = self.selected_text.pos1,
|
||||
datetime = datetime,
|
||||
notes = self.selected_text.text,
|
||||
highlighted = true,
|
||||
|
||||
@@ -40,11 +40,10 @@ function ReaderMenu:init()
|
||||
callback = function()
|
||||
self:onTapCloseMenu()
|
||||
self.ui:onClose()
|
||||
-- screen orientation is independent for docview and filemanager
|
||||
-- so we need to restore the screen mode for the filemanager
|
||||
local FileManager = require("apps/filemanager/filemanager")
|
||||
FileManager:restoreScreenMode()
|
||||
if not FileManager.is_running then
|
||||
if FileManager.instance then
|
||||
FileManager.instance:resetDimen(Screen:getSize())
|
||||
else
|
||||
local lastdir = nil
|
||||
local last_file = G_reader_settings:readSetting("lastfile")
|
||||
if last_file then
|
||||
@@ -59,8 +58,11 @@ function ReaderMenu:init()
|
||||
remember = false,
|
||||
callback = function()
|
||||
self:onTapCloseMenu()
|
||||
self.ui:onClose()
|
||||
UIManager:quit()
|
||||
UIManager:scheduleIn(0.1, function() self.ui:onClose() end)
|
||||
local FileManager = require("apps/filemanager/filemanager")
|
||||
if FileManager.instance then
|
||||
FileManager.instance:onClose()
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ function ReaderSearch:addToMainMenu(tab_item_table)
|
||||
end
|
||||
|
||||
function ReaderSearch:onShowSearchDialog(text)
|
||||
text = require("util").stripePunctuations(text)
|
||||
local do_search = function(search_func, text, param)
|
||||
return function()
|
||||
local res = search_func(self, text, param)
|
||||
|
||||
@@ -77,25 +77,36 @@ function ReaderToc:fillToc()
|
||||
self.toc = self.ui.document:getToc()
|
||||
end
|
||||
|
||||
function ReaderToc:getTocTitleByPage(pn_or_xp)
|
||||
function ReaderToc:getTocIndexByPage(pn_or_xp)
|
||||
self:fillToc()
|
||||
if #self.toc == 0 then return "" end
|
||||
if #self.toc == 0 then return end
|
||||
local pageno = pn_or_xp
|
||||
if type(pn_or_xp) == "string" then
|
||||
pageno = self.ui.document:getPageFromXPointer(pn_or_xp)
|
||||
end
|
||||
local pre_entry = self.toc[1]
|
||||
local pre_index = 1
|
||||
for _k,_v in ipairs(self.toc) do
|
||||
if _v.page > pageno then
|
||||
break
|
||||
end
|
||||
pre_entry = _v
|
||||
pre_index = _k
|
||||
end
|
||||
return pre_index
|
||||
end
|
||||
|
||||
function ReaderToc:getTocTitleByPage(pn_or_xp)
|
||||
local index = self:getTocIndexByPage(pn_or_xp)
|
||||
if index then
|
||||
return self:cleanUpTocTitle(self.toc[index].title)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
return self:cleanUpTocTitle(pre_entry.title)
|
||||
end
|
||||
|
||||
function ReaderToc:getTocTitleOfCurrentPage()
|
||||
return self:getTocTitleByPage(self.pageno)
|
||||
if self.pageno then
|
||||
return self:getTocTitleByPage(self.pageno)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderToc:getMaxDepth()
|
||||
@@ -220,10 +231,23 @@ function ReaderToc:getChapterPagesDone(pageno, level)
|
||||
end
|
||||
|
||||
function ReaderToc:updateCurrentNode()
|
||||
if #self.collapsed_toc > 0 then
|
||||
if #self.collapsed_toc > 0 and self.pageno then
|
||||
for i, v in ipairs(self.collapsed_toc) do
|
||||
if v.page > self.pageno then
|
||||
self.collapsed_toc.current = i > 1 and i - 1 or 1
|
||||
return
|
||||
end
|
||||
end
|
||||
self.collapsed_toc.current = #self.collapsed_toc
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderToc:expandCurrentNode()
|
||||
local current_node_index = self:getTocIndexByPage(self.pageno)
|
||||
if current_node_index then
|
||||
for i = current_node_index - 1, 1, -1 do
|
||||
if self.toc[i+1].depth > self.toc[i].depth then
|
||||
self:expandToc(i)
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -283,6 +307,7 @@ function ReaderToc:onShowToc()
|
||||
state_size = button_size,
|
||||
ui = self.ui,
|
||||
is_borderless = true,
|
||||
is_popout = false,
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
cface = Font:getFace("cfont", 20),
|
||||
@@ -323,6 +348,9 @@ function ReaderToc:onShowToc()
|
||||
|
||||
self.toc_menu = toc_menu
|
||||
|
||||
-- auto expand the parent node of current page
|
||||
self:expandCurrentNode()
|
||||
|
||||
UIManager:show(menu_container)
|
||||
|
||||
return true
|
||||
@@ -330,6 +358,9 @@ end
|
||||
|
||||
-- expand TOC node of index in raw toc table
|
||||
function ReaderToc:expandToc(index)
|
||||
for k, v in ipairs(self.expanded_nodes) do
|
||||
if v == index then return end
|
||||
end
|
||||
table.insert(self.expanded_nodes, index)
|
||||
local cur_node = self.toc[index]
|
||||
local cur_depth = cur_node.depth
|
||||
@@ -361,6 +392,12 @@ end
|
||||
|
||||
-- collapse TOC node of index in raw toc table
|
||||
function ReaderToc:collapseToc(index)
|
||||
for k, v in ipairs(self.expanded_nodes) do
|
||||
if v == index then
|
||||
table.remove(self.expanded_nodes, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
local cur_node = self.toc[index]
|
||||
local cur_depth = cur_node.depth
|
||||
local i = 1
|
||||
|
||||
@@ -23,6 +23,7 @@ table.insert(common_settings, {
|
||||
callback = function()
|
||||
local night_mode = G_reader_settings:readSetting("night_mode") or false
|
||||
Screen:toggleNightMode()
|
||||
UIManager:setDirty(nil, "full")
|
||||
G_reader_settings:saveSetting("night_mode", not night_mode)
|
||||
end
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ local OTAManager = {
|
||||
"http://hal9k.ifsc.usp.br:80/koreader/",
|
||||
},
|
||||
ota_channels = {
|
||||
"stable",
|
||||
"nightly",
|
||||
},
|
||||
zsync_template = "koreader-%s-latest-%s.zsync",
|
||||
@@ -23,6 +24,11 @@ local OTAManager = {
|
||||
updated_package = "ota/koreader.updated.tar",
|
||||
}
|
||||
|
||||
local ota_channels = {
|
||||
stable = _("stable"),
|
||||
nightly = _("develop"),
|
||||
}
|
||||
|
||||
function OTAManager:getOTAModel()
|
||||
if Device:isKindle() then
|
||||
return "kindle"
|
||||
@@ -65,11 +71,14 @@ function OTAManager:checkUpdate()
|
||||
local ota_zsync_file = self:getOTAServer() .. zsync_file
|
||||
local local_zsync_file = "ota/" .. zsync_file
|
||||
-- download zsync file from OTA server
|
||||
DEBUG("downloading zsync file", ota_zsync_file)
|
||||
local r, c, h = http.request{
|
||||
url = ota_zsync_file,
|
||||
sink = ltn12.sink.file(io.open(local_zsync_file, "w"))}
|
||||
-- prompt users to turn on Wifi if network is unreachable
|
||||
if c ~= 200 then return end
|
||||
if c ~= 200 then
|
||||
DEBUG("cannot find zsync file", c)
|
||||
return
|
||||
end
|
||||
-- parse OTA package version
|
||||
local ota_package = nil
|
||||
local zsync = io.open(local_zsync_file, "r")
|
||||
@@ -98,7 +107,7 @@ function OTAManager:checkUpdate()
|
||||
-- return ota package version if package on OTA server has version
|
||||
-- larger than the local package version
|
||||
if local_ok and ota_ok and ota_version and local_version and
|
||||
ota_version > local_version then
|
||||
ota_version ~= local_version then
|
||||
return ota_version, local_version
|
||||
elseif ota_version and ota_version == local_version then
|
||||
return 0
|
||||
@@ -113,7 +122,7 @@ function OTAManager:fetchAndProcessUpdate()
|
||||
})
|
||||
elseif ota_version == nil then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("OTA server is not available."),
|
||||
text = _("OTA package is not available."),
|
||||
})
|
||||
elseif ota_version then
|
||||
UIManager:show(ConfirmBox:new{
|
||||
@@ -184,7 +193,7 @@ function OTAManager:genChannelList()
|
||||
local channels = {}
|
||||
for _, channel in ipairs(self.ota_channels) do
|
||||
local channel_item = {
|
||||
text = channel,
|
||||
text = ota_channels[channel],
|
||||
checked_func = function() return self:getOTAChannel() == channel end,
|
||||
callback = function() self:setOTAChannel(channel) end
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ local FileChooser = Menu:extend{
|
||||
strcoll = strcoll,
|
||||
collate = "strcoll", -- or collate = "access",
|
||||
reverse_collate = false,
|
||||
path_pages = {}, -- store last browsed location(page) for each path
|
||||
path_items = {}, -- store last browsed location(item index) for each path
|
||||
}
|
||||
|
||||
function FileChooser:init()
|
||||
@@ -150,12 +150,11 @@ end
|
||||
|
||||
function FileChooser:updateItems(select_number)
|
||||
Menu.updateItems(self, select_number) -- call parent's updateItems()
|
||||
self.path_pages[self.path] = self.page
|
||||
self.path_items[self.path] = (self.page - 1) * self.perpage + (select_number or 1)
|
||||
end
|
||||
|
||||
function FileChooser:refreshPath()
|
||||
self.page = self.path_pages[self.path] or 1
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path), -1)
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path), self.path_items[self.path])
|
||||
end
|
||||
|
||||
function FileChooser:changeToPath(path)
|
||||
|
||||
@@ -575,8 +575,8 @@ function Menu:init()
|
||||
-- if the table is not yet initialized, this call
|
||||
-- must be done manually:
|
||||
self.page = math.ceil((self.item_table.current or 1) / self.perpage)
|
||||
self:updateItems(1)
|
||||
end
|
||||
self:updateItems(1)
|
||||
end
|
||||
|
||||
function Menu:onCloseWidget()
|
||||
|
||||
11
frontend/util.lua
Normal file
11
frontend/util.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
local util = {}
|
||||
|
||||
function util.stripePunctuations(word)
|
||||
if not word then return end
|
||||
-- strip ASCII punctuation characters around word
|
||||
-- and strip any generic punctuation (U+2000 - U+206F) in the word
|
||||
return word:gsub("\226[\128-\131][\128-\191]",''):gsub("^%p+",''):gsub("%p+$",'')
|
||||
end
|
||||
|
||||
return util
|
||||
Reference in New Issue
Block a user