From f25da5d0d54ca19d0f05f35e2d6434e32ad563dc Mon Sep 17 00:00:00 2001 From: zwim <36999612+zwim@users.noreply.github.com> Date: Mon, 31 May 2021 20:34:26 +0200 Subject: [PATCH] Hyphenation: add custom hyphenation rules (#7746) The hyphenation of a word can be changed from its default by long pressing for 3 seconds and selecting 'Hyphenate'. These overrides are stored in a per-language file, i.e: koreader/settings/user-German.hyph. --- base | 2 +- .../apps/reader/modules/readerdictionary.lua | 18 +- frontend/apps/reader/modules/readerfont.lua | 16 +- .../apps/reader/modules/readerhighlight.lua | 14 ++ .../apps/reader/modules/readertypeset.lua | 18 +- .../apps/reader/modules/readertypography.lua | 8 +- .../apps/reader/modules/readeruserhyph.lua | 228 ++++++++++++++++++ frontend/apps/reader/modules/readerview.lua | 8 +- frontend/apps/reader/readerui.lua | 7 + frontend/device/android/device.lua | 19 +- frontend/device/pocketbook/device.lua | 13 - frontend/device/thirdparty.lua | 6 +- frontend/document/credocument.lua | 19 ++ frontend/ui/uimanager.lua | 8 +- frontend/ui/widget/datewidget.lua | 1 + frontend/ui/widget/dictquicklookup.lua | 1 + frontend/ui/widget/doublespinwidget.lua | 1 + frontend/ui/widget/frontlightwidget.lua | 1 + frontend/ui/widget/imageviewer.lua | 1 + frontend/ui/widget/infomessage.lua | 5 +- frontend/ui/widget/inputdialog.lua | 1 - frontend/ui/widget/inputtext.lua | 17 +- frontend/ui/widget/keyboardlayoutdialog.lua | 1 + frontend/ui/widget/linkbox.lua | 1 + frontend/ui/widget/naturallightwidget.lua | 1 + frontend/ui/widget/notification.lua | 1 + frontend/ui/widget/openwithdialog.lua | 1 + frontend/ui/widget/qrmessage.lua | 1 + frontend/ui/widget/screensaverwidget.lua | 1 + frontend/ui/widget/skimtowidget.lua | 1 + frontend/ui/widget/spinwidget.lua | 1 + frontend/ui/widget/textviewer.lua | 1 + frontend/ui/widget/timewidget.lua | 1 + frontend/ui/widget/trapwidget.lua | 1 + frontend/ui/widget/virtualkeyboard.lua | 31 +-- platform/cervantes/koreader.sh | 94 +------- platform/pocketbook/koreader.app | 28 +-- plugins/opds.koplugin/opdsbrowser.lua | 18 +- plugins/opds.koplugin/opdsparser.lua | 16 +- 39 files changed, 355 insertions(+), 256 deletions(-) create mode 100644 frontend/apps/reader/modules/readeruserhyph.lua diff --git a/base b/base index 96c002d52..502bba07e 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 96c002d5260b09148def07913b5e4363d9a58c23 +Subproject commit 502bba07e57e652dcf85f0b2a5c6b1d52fbc0f75 diff --git a/frontend/apps/reader/modules/readerdictionary.lua b/frontend/apps/reader/modules/readerdictionary.lua index 06293296b..cd72bbf01 100644 --- a/frontend/apps/reader/modules/readerdictionary.lua +++ b/frontend/apps/reader/modules/readerdictionary.lua @@ -800,7 +800,7 @@ function ReaderDictionary:startSdcv(word, dict_names, fuzzy_search) -- dummy results final_results = { { - dict = _("Not available"), + dict = "", word = word, definition = lookup_cancelled and _("Dictionary lookup interrupted.") or _("No results."), no_result = true, @@ -849,22 +849,6 @@ function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, box, li return end - -- If the user disabled all the dictionaries, go away. - if dict_names and #dict_names == 0 then - -- Dummy result - local nope = { - { - dict = _("Not available"), - word = word, - definition = _("There are no enabled dictionaries.\nPlease check the 'Dictionary settings' menu."), - no_result = true, - lookup_cancelled = false, - } - } - self:showDict(word, nope, box, link) - return - end - self:showLookupInfo(word, self.lookup_msg_delay) self._lookup_start_tv = UIManager:getTime() diff --git a/frontend/apps/reader/modules/readerfont.lua b/frontend/apps/reader/modules/readerfont.lua index 6fd82b6c9..2deb7abca 100644 --- a/frontend/apps/reader/modules/readerfont.lua +++ b/frontend/apps/reader/modules/readerfont.lua @@ -209,7 +209,7 @@ function ReaderFont:onSetFontSize(new_size) self.font_size = new_size self.ui.document:setFontSize(Screen:scaleBySize(new_size)) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font size set to: %1."), self.font_size)) + Notification:notify(T(_("Font size set to %1."), self.font_size)) return true end @@ -217,7 +217,7 @@ function ReaderFont:onSetLineSpace(space) self.line_space_percent = math.min(200, math.max(50, space)) self.ui.document:setInterlineSpacePercent(self.line_space_percent) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Line spacing set to: %1%."), self.line_space_percent)) + Notification:notify(T(_("Line spacing set to %1%."), self.line_space_percent)) return true end @@ -225,7 +225,7 @@ function ReaderFont:onSetFontBaseWeight(weight) self.font_base_weight = weight self.ui.document:setFontBaseWeight(weight) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font weight set to: %1."), optionsutil:getOptionText("SetFontBaseWeight", weight))) + Notification:notify(T(_("Font weight set to %1."), optionsutil:getOptionText("SetFontBaseWeight", weight))) return true end @@ -233,7 +233,7 @@ function ReaderFont:onSetFontHinting(mode) self.font_hinting = mode self.ui.document:setFontHinting(mode) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font hinting set to: %1"), optionsutil:getOptionText("SetFontHinting", mode))) + Notification:notify(T(_("Font hinting set to %1."), optionsutil:getOptionText("SetFontHinting", mode))) return true end @@ -241,7 +241,7 @@ function ReaderFont:onSetFontKerning(mode) self.font_kerning = mode self.ui.document:setFontKerning(mode) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font kerning set to: %1"), optionsutil:getOptionText("SetFontKerning", mode))) + Notification:notify(T(_("Font kerning set to %1."), optionsutil:getOptionText("SetFontKerning", mode))) return true end @@ -249,7 +249,7 @@ function ReaderFont:onSetWordSpacing(values) self.word_spacing = values self.ui.document:setWordSpacing(values) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Word spacing set to: %1%, %2%"), values[1], values[2])) + Notification:notify(T(_("Word spacing set to %1%, %2%."), values[1], values[2])) return true end @@ -257,7 +257,7 @@ function ReaderFont:onSetWordExpansion(value) self.word_expansion = value self.ui.document:setWordExpansion(value) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Word expansion set to: %1%."), value)) + Notification:notify(T(_("Word expansion set to %1%."), value)) return true end @@ -266,7 +266,7 @@ function ReaderFont:onSetFontGamma(gamma) self.ui.document:setGammaIndex(self.gamma_index) local gamma_level = self.ui.document:getGammaLevel() self.ui:handleEvent(Event:new("RedrawCurrentView")) - Notification:notify(T(_("Font gamma set to: %1."), optionsutil:getOptionText("SetFontGamma", gamma_level))) + Notification:notify(T(_("Font gamma set to %1."), optionsutil:getOptionText("SetFontGamma", gamma_level))) return true end diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 48f627343..0d31ba4fc 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -169,6 +169,20 @@ function ReaderHighlight:init() } end) + -- User hyphenation dict + self:addToHighlightDialog("11_user_dict", function(_self) + return { + text= _("Hyphenate"), + show_in_highlight_dialog_func = function() + return _self.ui.userHyph and _self.ui.userhyph:isAvailable() and not _self.selected_text.text:find("[ ,;-%.\n]") + end, + callback = function() + _self.ui.userhyph:modifyUserEntry(_self.selected_text.text) + _self:onClose() + end, + } + end) + self.ui:registerPostInitCallback(function() self.ui.menu:registerToMainMenu(self) end) diff --git a/frontend/apps/reader/modules/readertypeset.lua b/frontend/apps/reader/modules/readertypeset.lua index 53e7afa60..c9e1b9179 100644 --- a/frontend/apps/reader/modules/readertypeset.lua +++ b/frontend/apps/reader/modules/readertypeset.lua @@ -138,27 +138,19 @@ end function ReaderTypeset:onToggleEmbeddedStyleSheet(toggle) self:toggleEmbeddedStyleSheet(toggle) - if toggle then - Notification:notify(_("Enabled embedded styles.")) - else - Notification:notify(_("Disabled embedded styles.")) - end + Notification:notify(T( _("Embedded styles are %1."), optionsutil:getOptionText("ToggleEmbeddedStyleSheet", toggle))) return true end function ReaderTypeset:onToggleEmbeddedFonts(toggle) self:toggleEmbeddedFonts(toggle) - if toggle then - Notification:notify(_("Enabled embedded fonts.")) - else - Notification:notify(_("Disabled embedded fonts.")) - end + Notification:notify(T( _("Embedded fonts are %1."), optionsutil:getOptionText("ToggleEmbeddedFonts", toggle))) return true end function ReaderTypeset:onToggleImageScaling(toggle) self:toggleImageScaling(toggle) - Notification:notify(T( _("Image scaling set to: %1"), optionsutil:getOptionText("ToggleImageScaling", toggle))) + Notification:notify(T( _("Image scaling set to %1."), optionsutil:getOptionText("ToggleImageScaling", toggle))) return true end @@ -169,7 +161,7 @@ end function ReaderTypeset:onSetBlockRenderingMode(mode) self:setBlockRenderingMode(mode) - Notification:notify(T( _("Render mode set to: %1"), optionsutil:getOptionText("SetBlockRenderingMode", mode))) + Notification:notify(T( _("Render mode set to %1."), optionsutil:getOptionText("SetBlockRenderingMode", mode))) return true end @@ -191,7 +183,7 @@ local OBSOLETED_CSS = { function ReaderTypeset:onSetRenderDPI(dpi) self:setRenderDPI(dpi) - Notification:notify(T( _("Zoom set to: %1"), optionsutil:getOptionText("SetRenderDPI", dpi))) + Notification:notify(T( _("Zoom set to %1."), optionsutil:getOptionText("SetRenderDPI", dpi))) return true end diff --git a/frontend/apps/reader/modules/readertypography.lua b/frontend/apps/reader/modules/readertypography.lua index 5ad82e922..660c4d7ea 100644 --- a/frontend/apps/reader/modules/readertypography.lua +++ b/frontend/apps/reader/modules/readertypography.lua @@ -237,6 +237,7 @@ When the book's language tag is not among our presets, no specific features will }) self.text_lang_tag = lang_tag self.ui.document:setTextMainLang(lang_tag) + self.ui:handleEvent(Event:new("TypographyLanguageChanged")) self.ui:handleEvent(Event:new("UpdatePos")) end, hold_callback = function(touchmenu_instance) @@ -427,8 +428,8 @@ These settings will apply to all books with any hyphenation dictionary. enabled_func = function() return self.hyphenation and not self.hyph_soft_hyphens_only end, - separator = true, }) + table.insert(hyphenation_submenu, self.ui.userhyph:getMenuEntry()) table.insert(hyphenation_submenu, { text_func = function() -- Show the current language default hyph dict (ie: English_US for zh) @@ -488,7 +489,7 @@ These settings will apply to all books with any hyphenation dictionary. end, }) table.insert(hyphenation_submenu, { - text = _("Soft-hyphens only"), + text = _("Soft hyphens only"), callback = function() self.hyph_soft_hyphens_only = not self.hyph_soft_hyphens_only self.hyph_force_algorithmic = false @@ -760,6 +761,7 @@ function ReaderTypography:onReadSettings(config) logger.dbg("Typography lang: no lang set, using", self.text_lang_tag) end self.ui.document:setTextMainLang(self.text_lang_tag) + self.ui:handleEvent(Event:new("TypographyLanguageChanged")) end function ReaderTypography:onPreRenderDocument(config) @@ -780,6 +782,7 @@ function ReaderTypography:onPreRenderDocument(config) self.text_lang_tag = self.book_lang_tag self.ui.doc_settings:saveSetting("text_lang", self.text_lang_tag) self.ui.document:setTextMainLang(self.text_lang_tag) + self.ui:handleEvent(Event:new("TypographyLanguageChanged")) self.ui:handleEvent(Event:new("UpdatePos")) end, enabled_func = function() @@ -809,6 +812,7 @@ function ReaderTypography:onPreRenderDocument(config) end self.text_lang_tag = self.book_lang_tag self.ui.document:setTextMainLang(self.text_lang_tag) + self.ui:handleEvent(Event:new("TypographyLanguageChanged")) end end diff --git a/frontend/apps/reader/modules/readeruserhyph.lua b/frontend/apps/reader/modules/readeruserhyph.lua new file mode 100644 index 000000000..c9863b349 --- /dev/null +++ b/frontend/apps/reader/modules/readeruserhyph.lua @@ -0,0 +1,228 @@ +local DataStorage = require("datastorage") +local Event = require("ui/event") +local FFIUtil = require("ffi/util") +local InfoMessage = require("ui/widget/infomessage") +local InputDialog = require("ui/widget/inputdialog") +local UIManager = require("ui/uimanager") +local WidgetContainer = require("ui/widget/container/widgetcontainer") +local lfs = require("libs/libkoreader-lfs") +local logger = require("logger") +local _ = require("gettext") +local T = require("ffi/util").template + +local ReaderUserHyph = WidgetContainer:new{ + -- return values from setUserHyphenationDict (crengine's UserHyphDict::init()) + USER_DICT_RELOAD = 0, + USER_DICT_NOCHANGE = 1, + USER_DICT_MALFORMED = 2, + USER_DICT_ERROR_NOT_SORTED = 3, +} + +-- returns path to the user dictionary +function ReaderUserHyph:getDictionaryPath() + return FFIUtil.joinPath(DataStorage:getSettingsDir(), + "user-" .. tostring(self.ui.document:getTextMainLangDefaultHyphDictionary():gsub(".pattern$", "")) .. ".hyph") +end + +-- Load the user dictionary suitable for the actual language +-- if reload==true, force a reload +-- Unload is done automatically when a new dictionary is loaded. +function ReaderUserHyph:loadDictionary(name, reload) + if G_reader_settings:isTrue("hyph_user_dict") and lfs.attributes(name, "mode") == "file" then + local ret = self.ui.document:setUserHyphenationDict(name, reload) + -- this should only happen, if a user edits a dictionary by hand or the user messed + -- with the dictionary file by hand. -> Warning and disable. + if ret == self.USER_DICT_ERROR_NOT_SORTED then + UIManager:show(InfoMessage:new{ + text = T(_("The user dictionary\n%1\nis not alphabetically sorted.\n\nIt has been disabled."), name), + }) + logger.warn("UserHyph: Dictionary " .. name .. " is not sorted alphabetically.") + G_reader_settings:makeFalse("hyph_user_dict") + elseif ret == self.USER_DICT_MALFORMED then + UIManager:show(InfoMessage:new{ + text = T(_("The user dictionary\n%1\nhas corrupted entries.\n\nOnly valid entries will be used."), name), + }) + logger.warn("UserHyph: Dictionary " .. name .. " has corrupted entries.") + end + else + self.ui.document:setUserHyphenationDict() -- clear crengine user hyph dict + end +end + +-- Reload on change of the hyphenation language +function ReaderUserHyph:onTypographyLanguageChanged() + self:loadUserDictionary() +end + +-- Reload on "ChangedUserDictionary" event, +-- doesn't load dictionary if filesize and filename haven't changed +-- if reload==true reload +function ReaderUserHyph:loadUserDictionary(reload) + self:loadDictionary(self:isAvailable() and self:getDictionaryPath() or "", reload and true or false) + self.ui:handleEvent(Event:new("UpdatePos")) +end + +-- Functions to use with the UI + +function ReaderUserHyph:isAvailable() + return G_reader_settings:isTrue("hyph_user_dict") and self:_enabled() +end + +function ReaderUserHyph:_enabled() + return self.ui.typography.hyphenation +end + +-- add Menu entry +function ReaderUserHyph:getMenuEntry() + return { + text = _("Custom hyphenation rules"), + help_text = _("The hyphenation of a word can be changed from its default by long pressing for 3 seconds and selecting 'Hyphenate'."), + callback = function() + local hyph_user_dict = not G_reader_settings:isTrue("hyph_user_dict") + G_reader_settings:saveSetting("hyph_user_dict", hyph_user_dict) + self:loadUserDictionary() -- not needed to force a reload here + end, + checked_func = function() + return self:isAvailable() + end, + enabled_func = function() + return self:_enabled() + end, + separator = true, + } +end + +-- Helper functions for dictionary entries------------------------------------------- + +-- checks if suggestion is well formated +function ReaderUserHyph:checkHyphenation(suggestion, word) + if suggestion:find("%-%-") then + return false -- two or more consecutive '-' + end + + suggestion = suggestion:gsub("-","") + if self.ui.document:getLowercasedWord(suggestion) == self.ui.document:getLowercasedWord(word) then + return true -- characters match (case insensitive) + end + return false +end + +function ReaderUserHyph:updateDictionary(word, hyphenation) + local dict_file = self:getDictionaryPath() + local new_dict_file = dict_file .. ".new" + + local new_dict = io.open(new_dict_file, "w") + if not new_dict then + logger.err("UserHyph: could not open " .. new_dict_file) + return + end + + local word_lower = self.ui.document:getLowercasedWord(word) + local line + + local dict = io.open(dict_file, "r") + if dict then + line = dict:read() + --search entry + while line and self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) < word_lower do + new_dict:write(line .. "\n") + line = dict:read() + end + + -- last word = nil if EOF, else last_word=word if found in file, else last_word is word after the new entry + if line then + local last_word = self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) + if last_word == self.ui.document:getLowercasedWord(word) then + line = nil -- word found + end + else + line = nil -- EOF + end + end + + -- write new entry + if hyphenation and hyphenation ~= "" then + new_dict:write(string.format("%s;%s\n", word, hyphenation)) + end + + -- write old entry if there was one + if line then + new_dict:write(line .. "\n") + end + + if dict then + repeat + line = dict:read() + if line then + new_dict:write(line .. "\n") + end + until (not line) + dict:close() + os.remove(dict_file) + end + + new_dict:close() + os.rename(new_dict_file, dict_file) + + self:loadUserDictionary(true) -- dictionary has changed, force a reload here +end + +function ReaderUserHyph:modifyUserEntry(word) + if word:find("[ ,;-%.]") then return end -- no button if more than one word + + if not self.ui.document then return end + + local suggested_hyphenation = self.ui.document:getHyphenationForWord(word) + + local input_dialog + input_dialog = InputDialog:new{ + title = T(_("Hyphenate: %1"), word), + description = _("Add hyphenation positions with hyphens ('-') or spaces (' ')."), + input = suggested_hyphenation, + old_hyph_lowercase = self.ui.document:getLowercasedWord(suggested_hyphenation), + input_type = "string", + buttons = { + { + { + text = _("Cancel"), + callback = function() + UIManager:close(input_dialog) + end, + }, + { + text = _("Remove"), + callback = function() + UIManager:close(input_dialog) + self:updateDictionary(word) + end, + }, + { + text = _("Save"), + is_enter_default = true, + callback = function() + local new_suggestion = input_dialog:getInputText() + new_suggestion = new_suggestion:gsub(" ","-") -- replace spaces with hyphens + new_suggestion = new_suggestion:gsub("^-","") -- remove leading hypenations + new_suggestion = new_suggestion:gsub("-$","") -- remove trailing hypenations + + if self:checkHyphenation(new_suggestion, word) then + -- don't save if no changes + if self.ui.document:getLowercasedWord(new_suggestion) ~= input_dialog.old_hyph_lowercase then + self:updateDictionary(word, new_suggestion) + end + UIManager:close(input_dialog) + else + UIManager:show(InfoMessage:new{ + text = T(_("Invalid hyphenation!"), self.dict_file), + }) + end + end, + }, + }, + }, + } + UIManager:show(input_dialog) + input_dialog:onShowKeyboard() +end + +return ReaderUserHyph diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index efc55d3ae..4b6132983 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -715,7 +715,7 @@ function ReaderView:onSetRotationMode(rotation) self.ui:handleEvent(Event:new("SetDimensions", new_screen_size)) self.ui:onScreenResize(new_screen_size) self.ui:handleEvent(Event:new("InitScrollPageStates")) - Notification:notify(T(_("Rotation mode set to: %1"), optionsutil:getOptionText("SetRotationMode", rotation))) + Notification:notify(T(_("Rotation mode set to %1."), optionsutil:getOptionText("SetRotationMode", rotation))) return true end @@ -849,12 +849,12 @@ function ReaderView:onGammaUpdate(gamma) if self.page_scroll then self.ui:handleEvent(Event:new("UpdateScrollPageGamma", gamma)) end - Notification:notify(T(_("Font gamma set to: %1."), gamma)) + Notification:notify(T(_("Font gamma set to %1."), gamma)) end function ReaderView:onFontSizeUpdate(font_size) self.ui:handleEvent(Event:new("ReZoom", font_size)) - Notification:notify(T(_("Font zoom set to: %1."), font_size)) + Notification:notify(T(_("Font zoom set to %1."), font_size)) end function ReaderView:onDefectSizeUpdate() @@ -874,7 +874,7 @@ function ReaderView:onSetViewMode(new_mode) self.view_mode = new_mode self.ui.document:setViewMode(new_mode) self.ui:handleEvent(Event:new("ChangeViewMode")) - Notification:notify(T( _("View mode set to: %1"), optionsutil:getOptionText("SetViewMode", new_mode))) + Notification:notify(T( _("View mode set to %1."), optionsutil:getOptionText("SetViewMode", new_mode))) end end diff --git a/frontend/apps/reader/readerui.lua b/frontend/apps/reader/readerui.lua index 85e0c7772..03452a04a 100644 --- a/frontend/apps/reader/readerui.lua +++ b/frontend/apps/reader/readerui.lua @@ -48,6 +48,7 @@ local ReaderStyleTweak = require("apps/reader/modules/readerstyletweak") local ReaderToc = require("apps/reader/modules/readertoc") local ReaderTypeset = require("apps/reader/modules/readertypeset") local ReaderTypography = require("apps/reader/modules/readertypography") +local ReaderUserHyph = require("apps/reader/modules/readeruserhyph") local ReaderView = require("apps/reader/modules/readerview") local ReaderWikipedia = require("apps/reader/modules/readerwikipedia") local ReaderZooming = require("apps/reader/modules/readerzooming") @@ -314,6 +315,12 @@ function ReaderUI:init() view = self.view, ui = self }) + -- user hyphenation (must be registered before typography) + self:registerModule("userhyph", ReaderUserHyph:new{ + dialog = self.dialog, + view = self.view, + ui = self + }) -- typography menu (replaces previous hyphenation menu / ReaderHyphenation) self:registerModule("typography", ReaderTypography:new{ dialog = self.dialog, diff --git a/frontend/device/android/device.lua b/frontend/device/android/device.lua index 47ac0e464..908442705 100644 --- a/frontend/device/android/device.lua +++ b/frontend/device/android/device.lua @@ -132,11 +132,10 @@ function Device:init() device = self, event_map = require("device/android/event_map"), handleMiscEv = function(this, ev) - local Event = require("ui/event") local UIManager = require("ui/uimanager") logger.dbg("Android application event", ev.code) if ev.code == C.APP_CMD_SAVE_STATE then - UIManager:broadcastEvent(Event:new("SaveSettings")) + return "SaveState" elseif ev.code == C.APP_CMD_DESTROY then UIManager:quit() elseif ev.code == C.APP_CMD_GAINED_FOCUS @@ -153,6 +152,7 @@ function Device:init() this.device.screen:resize() local new_size = this.device.screen:getSize() logger.info("Resizing screen to", new_size) + local Event = require("ui/event") local FileManager = require("apps/filemanager/filemanager") UIManager:broadcastEvent(Event:new("SetDimensions", new_size)) UIManager:broadcastEvent(Event:new("ScreenResize", new_size)) @@ -166,8 +166,10 @@ function Device:init() end end -- to-do: keyboard connected, disconnected - elseif ev.code == C.APP_CMD_RESUME then + elseif ev.code == C.APP_CMD_START then + local Event = require("ui/event") UIManager:broadcastEvent(Event:new("Resume")) + elseif ev.code == C.APP_CMD_RESUME then if external.when_back_callback then external.when_back_callback() external.when_back_callback = nil @@ -205,11 +207,14 @@ function Device:init() end end end - elseif ev.code == C.APP_CMD_PAUSE then + elseif ev.code == C.APP_CMD_STOP then + local Event = require("ui/event") UIManager:broadcastEvent(Event:new("Suspend")) elseif ev.code == C.AEVENT_POWER_CONNECTED then + local Event = require("ui/event") UIManager:broadcastEvent(Event:new("Charging")) elseif ev.code == C.AEVENT_POWER_DISCONNECTED then + local Event = require("ui/event") UIManager:broadcastEvent(Event:new("NotCharging")) elseif ev.code == C.AEVENT_DOWNLOAD_COMPLETE then android.ota.isRunning = false @@ -457,9 +462,9 @@ function Device:untar(archive, extract_to) end function Device:download(link, name, ok_text) + local UIManager = require("ui/uimanager") local ConfirmBox = require("ui/widget/confirmbox") local InfoMessage = require("ui/widget/infomessage") - local UIManager = require("ui/uimanager") local ok = android.download(link, name) if ok == C.ADOWNLOAD_EXISTS then self:install() @@ -479,14 +484,12 @@ function Device:download(link, name, ok_text) end function Device:install() - local ConfirmBox = require("ui/widget/confirmbox") - local Event = require("ui/event") local UIManager = require("ui/uimanager") + local ConfirmBox = require("ui/widget/confirmbox") UIManager:show(ConfirmBox:new{ text = _("Update is ready. Install it now?"), ok_text = _("Install"), ok_callback = function() - UIManager:broadcastEvent(Event:new("SaveSettings")) android.ota.install() android.ota.isPending = false end, diff --git a/frontend/device/pocketbook/device.lua b/frontend/device/pocketbook/device.lua index ed55ef5f9..1d10075ef 100644 --- a/frontend/device/pocketbook/device.lua +++ b/frontend/device/pocketbook/device.lua @@ -488,7 +488,6 @@ local PocketBook626 = PocketBook:new{ local PocketBook627 = PocketBook:new{ model = "PBLux4", display_dpi = 212, - isAlwaysPortrait = yes, } -- PocketBook Touch Lux 5 (628) @@ -577,16 +576,6 @@ local PocketBook740_2 = PocketBook:new{ } } --- PocketBook InkPad Color (741) -local PocketBook741 = PocketBook:new{ - model = "PBInkPadColor", - display_dpi = 300, - hasColorScreen = yes, - canUseCBB = no, -- 24bpp - isAlwaysPortrait = yes, - usingForcedRotation = landscape_ccw, -} - -- PocketBook Color Lux (801) local PocketBookColorLux = PocketBook:new{ model = "PBColorLux", @@ -673,8 +662,6 @@ elseif codename == "PB740" then return PocketBook740 elseif codename == "PB740-2" then return PocketBook740_2 -elseif codename == "PB741" then - return PocketBook741 elseif codename == "PocketBook 840" then return PocketBook840 elseif codename == "PB1040" then diff --git a/frontend/device/thirdparty.lua b/frontend/device/thirdparty.lua index 553fc8881..65bdfc41e 100644 --- a/frontend/device/thirdparty.lua +++ b/frontend/device/thirdparty.lua @@ -33,9 +33,7 @@ function M:new(o) end end end - if o.is_user_list then - logger.info(o:dump()) - end + logger.info(o:dump()) return o end @@ -56,7 +54,7 @@ function M:checkMethod(role, method) end function M:dump() - local str = "user defined thirdparty apps\n" + local str = (self.is_user_list and "user" or "platform") .. " thirdparty apps\n" for i, role in ipairs(roles) do local apps = self[role.."s"] for index, _ in ipairs(apps or {}) do diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index a8b52029c..745908e89 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -980,6 +980,25 @@ function CreDocument:setTextHyphenationSoftHyphensOnly(toggle) self._document:setStringProperty("crengine.textlang.hyphenation.soft.hyphens.only", toggle and 1 or 0) end +function CreDocument:setUserHyphenationDict(dict, reload) + logger.dbg("CreDocument: set textlang hyphenation dict", dict or "none") + return self._document:setUserHyphenationDict(dict or "", reload or false) +end + +function CreDocument:getHyphenationForWord(word) + if word then + return self._document:getHyphenationForWord(word) + end + return word +end + +function CreDocument:getLowercasedWord(word) + if word then + return self._document:getLowercasedWord(word) + end + return word +end + function CreDocument:setTextHyphenationForceAlgorithmic(toggle) logger.dbg("CreDocument: set textlang hyphenation force algorithmic", toggle) self._document:setStringProperty("crengine.textlang.hyphenation.force.algorithmic", toggle and 1 or 0) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index fa13cbe8a..6aca33208 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -467,16 +467,16 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) end logger.dbg("close widget:", widget.name or widget.id or tostring(widget)) local dirty = false - -- First notify the closed widget to save its settings... + -- Ensure all the widgets can get onFlushSettings event. widget:handleEvent(Event:new("FlushSettings")) - -- ...and notify it that it ought to be gone now. + -- first send close event to widget widget:handleEvent(Event:new("CloseWidget")) - -- Make sure it's disabled by default and check if there are any widgets that want it disabled or enabled. + -- make it disabled by default and check if any widget wants it disabled or enabled Input.disable_double_tap = true local requested_disable_double_tap = nil local is_covered = false local start_idx = 1 - -- Then remove all references to that widget on stack and refresh. + -- then remove all references to that widget on stack and refresh for i = #self._window_stack, 1, -1 do if self._window_stack[i].widget == widget then self._dirty[self._window_stack[i].widget] = nil diff --git a/frontend/ui/widget/datewidget.lua b/frontend/ui/widget/datewidget.lua index 2f3291523..4fdef411d 100644 --- a/frontend/ui/widget/datewidget.lua +++ b/frontend/ui/widget/datewidget.lua @@ -210,6 +210,7 @@ function DateWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.date_frame.dimen end) + return true end function DateWidget:onShow() diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index b2a345821..3d45cf472 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -909,6 +909,7 @@ function DictQuickLookup:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", nil end) + return true end function DictQuickLookup:onShow() diff --git a/frontend/ui/widget/doublespinwidget.lua b/frontend/ui/widget/doublespinwidget.lua index cfba7505a..e24e71e30 100644 --- a/frontend/ui/widget/doublespinwidget.lua +++ b/frontend/ui/widget/doublespinwidget.lua @@ -295,6 +295,7 @@ function DoubleSpinWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.widget_frame.dimen end) + return true end function DoubleSpinWidget:onShow() diff --git a/frontend/ui/widget/frontlightwidget.lua b/frontend/ui/widget/frontlightwidget.lua index c73f9af28..5fd241670 100644 --- a/frontend/ui/widget/frontlightwidget.lua +++ b/frontend/ui/widget/frontlightwidget.lua @@ -583,6 +583,7 @@ function FrontLightWidget:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", self.light_frame.dimen end) + return true end function FrontLightWidget:onShow() diff --git a/frontend/ui/widget/imageviewer.lua b/frontend/ui/widget/imageviewer.lua index 7cd9f5cd2..c69eff1f4 100644 --- a/frontend/ui/widget/imageviewer.lua +++ b/frontend/ui/widget/imageviewer.lua @@ -850,6 +850,7 @@ function ImageViewer:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", self.main_frame.dimen end) + return true end return ImageViewer diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index 7ae72ff08..dec9f6d75 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -206,15 +206,16 @@ function InfoMessage:onCloseWidget() end if self.invisible then -- Still invisible, no setDirty needed - return + return true end if self.no_refresh_on_close then - return + return true end UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) + return true end function InfoMessage:onShow() diff --git a/frontend/ui/widget/inputdialog.lua b/frontend/ui/widget/inputdialog.lua index f5609ffcb..759acd736 100644 --- a/frontend/ui/widget/inputdialog.lua +++ b/frontend/ui/widget/inputdialog.lua @@ -391,7 +391,6 @@ function InputDialog:init() scroll_callback = self._buttons_scroll_callback, -- nil if no Nav or Scroll buttons scroll = true, scroll_by_pan = self.scroll_by_pan, - has_nav_bar = self.add_nav_bar, cursor_at_end = self.cursor_at_end, readonly = self.readonly, parent = self, diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index d565264cc..2483b76ab 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -61,7 +61,6 @@ local InputText = InputContainer:new{ for_measurement_only = nil, -- When the widget is a one-off used to compute text height do_select = false, -- to start text selection selection_start_pos = nil, -- selection start position - is_keyboard_hidden = false, -- to be able to show the keyboard again when it was hidden (by VK itself) } -- only use PhysicalKeyboard if the device does not have touch screen @@ -122,11 +121,6 @@ if Device:isTouchDevice() or Device:hasDPad() then function InputText:onTapTextBox(arg, ges) if self.parent.onSwitchFocus then self.parent:onSwitchFocus(self) - else - if self.is_keyboard_hidden == true then - self:onShowKeyboard() - self.is_keyboard_hidden = false - end end if #self.charlist > 0 then -- Avoid cursor moving within a hint. local textwidget_offset = self.margin + self.bordersize + self.padding @@ -569,21 +563,12 @@ end function InputText:onShowKeyboard(ignore_first_hold_release) Device:startTextInput() + self.keyboard.ignore_first_hold_release = ignore_first_hold_release UIManager:show(self.keyboard) return true end -function InputText:onHideKeyboard() - if not self.has_nav_bar then - UIManager:close(self.keyboard) - Device:stopTextInput() - self.is_keyboard_hidden = true - end - - return self.is_keyboard_hiddenend -end - function InputText:onCloseKeyboard() UIManager:close(self.keyboard) Device:stopTextInput() diff --git a/frontend/ui/widget/keyboardlayoutdialog.lua b/frontend/ui/widget/keyboardlayoutdialog.lua index 5296afcd6..8fadc4439 100644 --- a/frontend/ui/widget/keyboardlayoutdialog.lua +++ b/frontend/ui/widget/keyboardlayoutdialog.lua @@ -157,6 +157,7 @@ function KeyboardLayoutDialog:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) + return true end return KeyboardLayoutDialog diff --git a/frontend/ui/widget/linkbox.lua b/frontend/ui/widget/linkbox.lua index 1003621a9..59f03bf65 100644 --- a/frontend/ui/widget/linkbox.lua +++ b/frontend/ui/widget/linkbox.lua @@ -38,6 +38,7 @@ function LinkBox:onCloseWidget() UIManager:setDirty(nil, function() return "partial", self.box end) + return true end function LinkBox:onShow() diff --git a/frontend/ui/widget/naturallightwidget.lua b/frontend/ui/widget/naturallightwidget.lua index d10714b0c..594b65ce5 100644 --- a/frontend/ui/widget/naturallightwidget.lua +++ b/frontend/ui/widget/naturallightwidget.lua @@ -381,6 +381,7 @@ function NaturalLightWidget:onCloseWidget() end) -- Tell frontlight widget that we're closed self.fl_widget:naturalLightConfigClose() + return true end function NaturalLightWidget:onShow() diff --git a/frontend/ui/widget/notification.lua b/frontend/ui/widget/notification.lua index 13b815b6f..c4c9ceccf 100644 --- a/frontend/ui/widget/notification.lua +++ b/frontend/ui/widget/notification.lua @@ -182,6 +182,7 @@ function Notification:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.frame.dimen end) + return true end function Notification:onShow() diff --git a/frontend/ui/widget/openwithdialog.lua b/frontend/ui/widget/openwithdialog.lua index cf8acc982..8bb1b377a 100644 --- a/frontend/ui/widget/openwithdialog.lua +++ b/frontend/ui/widget/openwithdialog.lua @@ -188,6 +188,7 @@ function OpenWithDialog:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.dialog_frame.dimen end) + return true end return OpenWithDialog diff --git a/frontend/ui/widget/qrmessage.lua b/frontend/ui/widget/qrmessage.lua index 684bbb2aa..cb39d2d86 100644 --- a/frontend/ui/widget/qrmessage.lua +++ b/frontend/ui/widget/qrmessage.lua @@ -86,6 +86,7 @@ function QRMessage:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) + return true end function QRMessage:onShow() diff --git a/frontend/ui/widget/screensaverwidget.lua b/frontend/ui/widget/screensaverwidget.lua index 2d004241a..d03f0a70d 100644 --- a/frontend/ui/widget/screensaverwidget.lua +++ b/frontend/ui/widget/screensaverwidget.lua @@ -88,6 +88,7 @@ function ScreenSaverWidget:onCloseWidget() UIManager:setDirty(nil, function() return "full", self.main_frame.dimen end) + return true end return ScreenSaverWidget diff --git a/frontend/ui/widget/skimtowidget.lua b/frontend/ui/widget/skimtowidget.lua index b6b1bcadb..d7ec7fbdb 100644 --- a/frontend/ui/widget/skimtowidget.lua +++ b/frontend/ui/widget/skimtowidget.lua @@ -338,6 +338,7 @@ function SkimToWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.skimto_frame.dimen end) + return true end function SkimToWidget:onShow() diff --git a/frontend/ui/widget/spinwidget.lua b/frontend/ui/widget/spinwidget.lua index a2d5b1c52..b83d15477 100644 --- a/frontend/ui/widget/spinwidget.lua +++ b/frontend/ui/widget/spinwidget.lua @@ -248,6 +248,7 @@ function SpinWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.spin_frame.dimen end) + return true end function SpinWidget:onShow() diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index 096e5ac38..602c957f2 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -229,6 +229,7 @@ function TextViewer:onCloseWidget() UIManager:setDirty(nil, function() return "partial", self.frame.dimen end) + return true end function TextViewer:onShow() diff --git a/frontend/ui/widget/timewidget.lua b/frontend/ui/widget/timewidget.lua index a3bf01a02..63bd95aac 100644 --- a/frontend/ui/widget/timewidget.lua +++ b/frontend/ui/widget/timewidget.lua @@ -195,6 +195,7 @@ function TimeWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.time_frame.dimen end) + return true end function TimeWidget:onShow() diff --git a/frontend/ui/widget/trapwidget.lua b/frontend/ui/widget/trapwidget.lua index b33d14b98..7dba76521 100644 --- a/frontend/ui/widget/trapwidget.lua +++ b/frontend/ui/widget/trapwidget.lua @@ -155,6 +155,7 @@ function TrapWidget:onCloseWidget() return "ui", self.frame.dimen end) end + return true end return TrapWidget diff --git a/frontend/ui/widget/virtualkeyboard.lua b/frontend/ui/widget/virtualkeyboard.lua index 5dbd4868d..519a30c7d 100644 --- a/frontend/ui/widget/virtualkeyboard.lua +++ b/frontend/ui/widget/virtualkeyboard.lua @@ -111,7 +111,7 @@ function VirtualKey:init() self.keyboard:delToStartOfLine() end --self.skiphold = true - elseif self.label == "←" then + elseif self.label =="←" then self.callback = function() self.keyboard:leftChar() end self.hold_callback = function() self.ignore_key_release = true @@ -127,13 +127,6 @@ function VirtualKey:init() self.callback = function() self.keyboard:upLine() end elseif self.label == "↓" then self.callback = function() self.keyboard:downLine() end - self.hold_callback = function() - self.ignore_key_release = true - if not self.keyboard:onHideKeyboard() then - -- Keyboard was *not* actually hidden: refresh the key to clear the highlight - self:update_keyboard(false, true) - end - end else self.callback = function () self.keyboard:addChar(self.key) end self.hold_callback = function() @@ -527,17 +520,6 @@ function VirtualKeyPopup:init() virtual_key.hold_callback = nil -- close popup on hold release virtual_key.onHoldReleaseKey = function() - -- NOTE: Check our *parent* key! - if parent_key.ignore_key_release then - parent_key.ignore_key_release = nil - return true - end - Device:performHapticFeedback("LONG_PRESS") - if virtual_key.keyboard.ignore_first_hold_release then - virtual_key.keyboard.ignore_first_hold_release = false - return true - end - virtual_key:onTapSelect(true) UIManager:close(self) return true @@ -648,19 +630,13 @@ function VirtualKeyPopup:init() } if position_container.dimen.x < 0 then position_container.dimen.x = 0 - -- We effectively move the popup, which means the key underneath our finger may no longer *exactly* be parent_key. - -- Make sure we won't close the popup right away, as that would risk being a *different* key, in order to make that less confusing. - parent_key.ignore_key_release = true elseif position_container.dimen.x + keyboard_frame.dimen.w > Screen:getWidth() then position_container.dimen.x = Screen:getWidth() - keyboard_frame.dimen.w - parent_key.ignore_key_release = true end if position_container.dimen.y < 0 then position_container.dimen.y = 0 - parent_key.ignore_key_release = true elseif position_container.dimen.y + keyboard_frame.dimen.h > Screen:getHeight() then position_container.dimen.y = Screen:getHeight() - keyboard_frame.dimen.h - parent_key.ignore_key_release = true end self[1] = position_container @@ -769,10 +745,6 @@ function VirtualKeyboard:onClose() return true end -function VirtualKeyboard:onHideKeyboard() - return self.inputbox:onHideKeyboard() -end - function VirtualKeyboard:onPressKey() self:getFocusItem():handleEvent(Event:new("TapSelect")) return true @@ -799,6 +771,7 @@ end function VirtualKeyboard:onCloseWidget() self:_refresh(false) + return true end function VirtualKeyboard:initLayer(layer) diff --git a/platform/cervantes/koreader.sh b/platform/cervantes/koreader.sh index 6f975f88d..3bdb84424 100755 --- a/platform/cervantes/koreader.sh +++ b/platform/cervantes/koreader.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh export LC_ALL="en_US.UTF-8" @@ -83,9 +83,6 @@ if [ "${STANDALONE}" != "true" ]; then [ -x /etc/init.d/connman ] && /etc/init.d/connman stop fi -CRASH_COUNT=0 -CRASH_TS=0 -CRASH_PREV_TS=0 # **magic** values to request shell stuff. It starts at 85, # any number lower than that will exit this script. RESTART_KOREADER=85 @@ -94,101 +91,18 @@ ENTER_QBOOKAPP=87 RETURN_VALUE="${RESTART_KOREADER}" # Loop forever until KOReader requests a normal exit. -while [ "${RETURN_VALUE}" -ne 0 ]; do +while [ "${RETURN_VALUE}" -ge "${RESTART_KOREADER}" ]; do # move dictionaries from external storage to koreader private partition. find /mnt/public/dict -type f -exec mv -v \{\} /mnt/private/koreader/data/dict \; 2>/dev/null - if [ ${RETURN_VALUE} -eq ${RESTART_KOREADER} ]; then - # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). - ko_update_check - fi + # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). + ko_update_check # run KOReader ./reader.lua "$@" >>crash.log 2>&1 RETURN_VALUE=$? - if [ ${RETURN_VALUE} -ne 0 ] && [ "${RETURN_VALUE}" -ne "${ENTER_USBMS}" ] && [ "${RETURN_VALUE}" -ne "${ENTER_QBOOKAPP}" ] && [ "${RETURN_VALUE}" -ne "${RESTART_KOREADER}" ]; then - # Increment the crash counter - CRASH_COUNT=$((CRASH_COUNT + 1)) - CRASH_TS=$(date +'%s') - # Reset it to a first crash if it's been a while since our last crash... - if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then - CRASH_COUNT=1 - fi - - # Check if the user requested to always abort on crash - if grep -q '\["dev_abort_on_crash"\] = true' 'settings.reader.lua' 2>/dev/null; then - ALWAYS_ABORT="true" - # In which case, make sure we pause on *every* crash - CRASH_COUNT=1 - else - ALWAYS_ABORT="false" - fi - - # Show a fancy bomb on screen - viewWidth=600 - viewHeight=800 - FONTH=16 - eval "$(./fbink -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')" - # Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device. - # Height @ ~56.7%, w/ a margin worth 1.5 lines - bombHeight=$((viewHeight / 2 + viewHeight / 15)) - bombMargin=$((FONTH + FONTH / 2)) - # With a little notice at the top of the screen, on a big gray screen of death ;). - ./fbink -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" - if [ ${CRASH_COUNT} -eq 1 ]; then - # Warn that we're waiting on a tap to continue... - ./fbink -q -b -O -m -y 2 "Tap the screen to continue." - fi - # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... - ./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3' - # And then print the tail end of the log on the bottom of the screen... - crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" - # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi - ./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}" - # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. - ./fbink -q -f -s - # Cue a lemming's faceplant sound effect! - - { - echo "!!!!" - echo "Uh oh, something went awry... (Crash n°${CRASH_COUNT}: $(date +'%x @ %X'))" - echo "Running on Linux $(uname -r) ($(uname -v))" - } >>crash.log 2>&1 - if [ ${CRASH_COUNT} -lt 5 ] && [ "${ALWAYS_ABORT}" = "false" ]; then - echo "Attempting to restart KOReader . . ." >>crash.log 2>&1 - echo "!!!!" >>crash.log 2>&1 - fi - - # Pause a bit if it's the first crash in a while, so that it actually has a chance of getting noticed ;). - if [ ${CRASH_COUNT} -eq 1 ]; then - # NOTE: We don't actually care about what head reads, we're just using it as a fancy sleep ;). - # i.e., we pause either until the 15s timeout, or until the user touches the screen. - timeout 15 head -c 24 /dev/input/event1 >/dev/null - fi - # Cycle the last crash timestamp - CRASH_PREV_TS=${CRASH_TS} - - # But if we've crashed more than 5 consecutive times, exit, because we wouldn't want to be stuck in a loop... - # NOTE: No need to check for ALWAYS_ABORT, CRASH_COUNT will always be 1 when it's true ;). - if [ ${CRASH_COUNT} -ge 5 ]; then - echo "Too many consecutive crashes, aborting . . ." >>crash.log 2>&1 - echo "!!!! ! !!!!" >>crash.log 2>&1 - break - fi - - # If the user requested to always abort on crash, do so. - if [ "${ALWAYS_ABORT}" = "true" ]; then - echo "Aborting . . ." >>crash.log 2>&1 - echo "!!!! ! !!!!" >>crash.log 2>&1 - break - fi - else - # Reset the crash counter if that was a sane exit/restart - CRASH_COUNT=0 - fi - # check if KOReader requested to enter in mass storage mode. if [ "${RETURN_VALUE}" -eq "${ENTER_USBMS}" ]; then # NOTE: at this point we're sure that the safemode tool diff --git a/platform/pocketbook/koreader.app b/platform/pocketbook/koreader.app index 2f3ad9b8d..cf8ea5529 100755 --- a/platform/pocketbook/koreader.app +++ b/platform/pocketbook/koreader.app @@ -33,16 +33,13 @@ ko_update_check() { # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" - # shellcheck disable=SC2003 - BLOCKS="$(expr "${FILESIZE}" / 20)" - # shellcheck disable=SC2003 - CPOINTS="$(expr "${BLOCKS}" / 100)" - export CPOINTS + BLOCKS="$((FILESIZE / 20))" + export CPOINTS="$((BLOCKS / 100))" # NOTE: We don't run as root, but folders created over USBMS are owned by root, which yields fun permission shenanigans... # c.f., https://github.com/koreader/koreader/issues/7581 KO_PB_TARLOG="/tmp/.koreader.tar" # shellcheck disable=SC2016 - "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $(expr ${TAR_CHECKPOINT} / ${CPOINTS}) > ${FBINK_NAMED_PIPE}' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" + "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" fail=$? kill -TERM "${FBINK_PID}" # As mentioned above, filter out potential chmod & utime failures... @@ -119,12 +116,10 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do # Did we crash? if [ "${RETURN_VALUE}" -ne 0 ] && [ "${RETURN_VALUE}" -ne ${KO_RC_RESTART} ]; then # Increment the crash counter - # shellcheck disable=SC2003 - CRASH_COUNT="$(expr ${CRASH_COUNT} + 1)" - CRASH_TS="$(date +'%s')" + CRASH_COUNT=$((CRASH_COUNT + 1)) + CRASH_TS=$(date +'%s') # Reset it to a first crash if it's been a while since our last crash... - # shellcheck disable=SC2003 - if [ "$(expr "${CRASH_TS}" - "${CRASH_PREV_TS}")" -ge 20 ]; then + if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then CRASH_COUNT=1 fi @@ -144,10 +139,8 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do eval "$("${KOREADER_DIR}/fbink" -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')" # Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device. # Height @ ~56.7%, w/ a margin worth 1.5 lines - # shellcheck disable=SC2003 - bombHeight="$(expr ${viewHeight} / 2 + ${viewHeight} / 15)" - # shellcheck disable=SC2003 - bombMargin="$(expr ${FONTH} + ${FONTH} / 2)" + bombHeight=$((viewHeight / 2 + viewHeight / 15)) + bombMargin=$((FONTH + FONTH / 2)) # With a little notice at the top of the screen, on a big gray screen of death ;). "${KOREADER_DIR}/fbink" -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" if [ ${CRASH_COUNT} -eq 1 ]; then @@ -156,12 +149,11 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do fi # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... # shellcheck disable=SC2039,SC3003 - "${KOREADER_DIR}/fbink" -q -b -O -m -t regular=${KOREADER_DIR}/fonts/freefont/FreeSerif.ttf,px="${bombHeight}",top="${bombMargin}" -- $'\xf0\x9f\x92\xa3' + "${KOREADER_DIR}/fbink" -q -b -O -m -t regular=${KOREADER_DIR}/fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3' # And then print the tail end of the log on the bottom of the screen... crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi - # shellcheck disable=SC2003 - "${KOREADER_DIR}/fbink" -q -b -O -t regular=${KOREADER_DIR}/fonts/droid/DroidSansMono.ttf,top="$(expr ${viewHeight} / 2 + ${FONTH} '*' 2 + ${FONTH} / 2)",left="$(expr ${viewWidth} / 60)",right="$(expr ${viewWidth} / 60)",px="$(expr ${viewHeight} / 64)" -- "${crashLog}" + "${KOREADER_DIR}/fbink" -q -b -O -t regular=${KOREADER_DIR}/fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}" # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. ${KOREADER_DIR}/fbink -q -f -s # Cue a lemming's faceplant sound effect! diff --git a/plugins/opds.koplugin/opdsbrowser.lua b/plugins/opds.koplugin/opdsbrowser.lua index 8715a23d5..d8b0ac00f 100644 --- a/plugins/opds.koplugin/opdsbrowser.lua +++ b/plugins/opds.koplugin/opdsbrowser.lua @@ -612,7 +612,6 @@ end function OPDSBrowser:createNewDownloadDialog(path, buttons) self.download_dialog = ButtonDialogTitle:new{ title = T(_("Download folder:\n%1\n\nDownload file type:"), BD.dirpath(path)), - use_info_style = true, buttons = buttons } end @@ -651,10 +650,10 @@ function OPDSBrowser:showDownloads(item) table.insert(buttons, line) end table.insert(buttons, {}) - -- Set download folder and book info buttons. + -- Set download folder button. table.insert(buttons, { { - text = _("Select folder"), + text = _("Select another folder"), callback = function() require("ui/downloadmgr"):new{ onConfirm = function(path) @@ -668,18 +667,7 @@ function OPDSBrowser:showDownloads(item) end, }:chooseDir() end, - }, - { - text = _("Book information"), - enabled = type(item.content) == "string", - callback = function() - local TextViewer = require("ui/widget/textviewer") - UIManager:show(TextViewer:new{ - title = item.text, - text = util.htmlToPlainTextIfHtml(item.content), - }) - end, - }, + } }) self:createNewDownloadDialog(self.getCurrentDownloadDir(), buttons) diff --git a/plugins/opds.koplugin/opdsparser.lua b/plugins/opds.koplugin/opdsparser.lua index a1c247a99..20ee727ed 100644 --- a/plugins/opds.koplugin/opdsparser.lua +++ b/plugins/opds.koplugin/opdsparser.lua @@ -72,6 +72,10 @@ function OPDSParser:createFlatXTable(xlex, curr_element) end function OPDSParser:parse(text) + -- Murder Calibre's whole "content" block, because luxl doesn't really deal well with various XHTML quirks, + -- as the list of crappy replacements below attests to... + -- There's also a high probability of finding orphaned tags or badly nested ones in there, which will screw everything up. + text = text:gsub('.-', '') -- luxl doesn't handle XML comments, so strip them text = text:gsub("", "") -- luxl is also particular about the syntax for self-closing, empty & orphaned tags... @@ -80,18 +84,8 @@ function OPDSParser:parse(text) text = text:gsub("<([bh]r)>", "<%1 />") -- Some OPDS catalogs wrap text in a CDATA section, remove it as it causes parsing problems text = text:gsub("", function (s) - return s:gsub("%p", {["&"] = "&", ["<"] = "<", [">"] = ">"}) + return s:gsub( "%p", {["&"] = "&", ["<"] = "<", [">"] = ">" } ) end ) - - -- NOTE: OPDS content tags are likely to contain a bunch of HTML or XHTML. We do *NOT* want to let luxl parse that, - -- because it doesn't really deal well with various XHTML quirks, as the list of crappy replacements above attests to... - -- There's also a high probability of finding orphaned tags or badly nested ones in there, which would screw everything up. - -- In any case, we just want to treat the whole thing as a single text node anyway, so, just mangle the markup to force luxl's hand. - text = text:gsub('', "") - text = text:gsub("(.-)", function (s) - return '' .. s:gsub("%p", {["<"] = "<", [">"] = ">", ['"'] = """, ["'"] = "'"}) .. "" - end ) - local xlex = luxl.new(text, #text) return assert(self:createFlatXTable(xlex)) end