mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
[plugin] Vocabulary builder bugfix and quick word deletion (#9168)
This PR fixes the bug #9162 caused by unsafe db operation and adds an edit mode for quick deletion of words requested at #9132 (comment)
This commit is contained in:
@@ -203,21 +203,26 @@ end
|
||||
|
||||
function VocabularyBuilder:insertOrUpdate(entry)
|
||||
local conn = SQ3.open(db_location)
|
||||
|
||||
conn:exec(string.format([[INSERT INTO vocabulary (word, book_title, create_time, due_time)
|
||||
VALUES ('%s', '%s', %d, %d)
|
||||
local stmt = conn:prepare([[INSERT INTO vocabulary (word, book_title, create_time, due_time)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(word) DO UPDATE SET book_title = excluded.book_title,
|
||||
create_time = excluded.create_time,
|
||||
review_count = MAX(review_count-1, 0),
|
||||
due_time = %d;
|
||||
]], entry.word, entry.book_title, entry.time, entry.time+300, entry.time+300))
|
||||
due_time = ?;]])
|
||||
stmt:bind(entry.word, entry.book_title, entry.time, entry.time+300, entry.time+300)
|
||||
stmt:step()
|
||||
stmt:clearbind():reset()
|
||||
self.count = tonumber(conn:rowexec("SELECT count(0) from vocabulary;"))
|
||||
conn:close()
|
||||
end
|
||||
|
||||
function VocabularyBuilder:remove(item)
|
||||
local conn = SQ3.open(db_location)
|
||||
conn:exec(string.format("DELETE FROM vocabulary WHERE word = '%s' ;", item.word))
|
||||
local stmt = conn:prepare("DELETE FROM vocabulary WHERE word = ? ;")
|
||||
stmt:bind(item.word)
|
||||
stmt:step()
|
||||
stmt:clearbind():reset()
|
||||
|
||||
self.count = self.count - 1
|
||||
conn:close()
|
||||
end
|
||||
@@ -229,13 +234,6 @@ function VocabularyBuilder:resetProgress()
|
||||
conn:close()
|
||||
end
|
||||
|
||||
function VocabularyBuilder:resetWordProgress(word)
|
||||
local conn = SQ3.open(db_location)
|
||||
local due_time = os.time()
|
||||
conn:exec(string.format("UPDATE vocabulary SET review_count = 0, due_time = %d WHERE word = '%s';", due_time, word))
|
||||
conn:close()
|
||||
end
|
||||
|
||||
function VocabularyBuilder:purge()
|
||||
local conn = SQ3.open(db_location)
|
||||
conn:exec("DELETE FROM vocabulary;")
|
||||
|
||||
@@ -54,6 +54,8 @@ Menu dialogue widget
|
||||
--]]--
|
||||
local MenuDialog = FocusManager:new{
|
||||
padding = Size.padding.fullscreen,
|
||||
is_edit_mode = false,
|
||||
edit_callback = nil,
|
||||
tap_close_callback = nil,
|
||||
clean_callback = nil,
|
||||
reset_callback = nil,
|
||||
@@ -99,6 +101,14 @@ function MenuDialog:init()
|
||||
switch:setPosition(settings.enabled and 2 or 1)
|
||||
self:mergeLayoutInVertical(switch)
|
||||
|
||||
local edit_button = {
|
||||
text = self.is_edit_mode and _("Resume") or _("Quick deletion"),
|
||||
callback = function()
|
||||
self:onClose()
|
||||
self.edit_callback()
|
||||
end
|
||||
}
|
||||
|
||||
local reset_button = {
|
||||
text = _("Reset all progress"),
|
||||
callback = function()
|
||||
@@ -132,6 +142,7 @@ function MenuDialog:init()
|
||||
local buttons = ButtonTable:new{
|
||||
width = width,
|
||||
buttons = {
|
||||
{edit_button},
|
||||
{reset_button},
|
||||
{clean_button}
|
||||
},
|
||||
@@ -451,7 +462,7 @@ function VocabItemWidget:initItemWidget()
|
||||
|
||||
table.insert(self.layout, word_widget)
|
||||
|
||||
if self.item.review_count < 5 then
|
||||
if not self.show_parent.is_edit_mode and self.item.review_count < 5 then
|
||||
self.more_button = Button:new{
|
||||
text = "⋮",
|
||||
padding = Size.padding.button,
|
||||
@@ -477,7 +488,7 @@ function VocabItemWidget:initItemWidget()
|
||||
|
||||
local right_side_width
|
||||
local right_widget
|
||||
if self.item.due_time <= os.time() then
|
||||
if not self.show_parent.is_edit_mode and self.item.due_time <= os.time() then
|
||||
right_side_width = review_button_width * 2 + Size.padding.large * 2 + ellipsis_button_width
|
||||
|
||||
self.forgot_button = Button:new{
|
||||
@@ -690,6 +701,9 @@ function VocabItemWidget:onGotIt()
|
||||
self.item.got_it_callback(self.item)
|
||||
self.item.is_dim = true
|
||||
self:initItemWidget()
|
||||
if self.show_parent.selected.x == 3 then
|
||||
self.show_parent.selected.x = 1
|
||||
end
|
||||
UIManager:setDirty(self.show_parent, function()
|
||||
return "ui", self[1].dimen end)
|
||||
end
|
||||
@@ -718,6 +732,7 @@ local VocabularyBuilderWidget = FocusManager:new{
|
||||
show_page = 1,
|
||||
-- table of items
|
||||
item_table = nil, -- mandatory (array)
|
||||
is_edit_mode = false,
|
||||
callback = nil,
|
||||
}
|
||||
|
||||
@@ -746,7 +761,6 @@ function VocabularyBuilderWidget:init()
|
||||
self.item_width = self.dimen.w - 2 * padding
|
||||
self.footer_center_width = math.floor(self.width_widget * 32 / 100)
|
||||
self.footer_button_width = math.floor(self.width_widget * 12 / 100)
|
||||
self.item_height = Screen:scaleBySize(72)
|
||||
-- group for footer
|
||||
local chevron_left = "chevron.left"
|
||||
local chevron_right = "chevron.right"
|
||||
@@ -834,6 +848,7 @@ function VocabularyBuilderWidget:init()
|
||||
bottom_line,
|
||||
self.page_info,
|
||||
}
|
||||
self.footer_height = vertical_footer:getSize().h
|
||||
local footer = BottomContainer:new{
|
||||
dimen = self.dimen:copy(),
|
||||
vertical_footer,
|
||||
@@ -853,13 +868,7 @@ function VocabularyBuilderWidget:init()
|
||||
show_parent = self,
|
||||
}
|
||||
|
||||
-- setup main content
|
||||
self.item_margin = math.floor(self.item_height / 8)
|
||||
local line_height = self.item_height + self.item_margin
|
||||
local content_height = self.dimen.h - self.title_bar:getHeight() - vertical_footer:getSize().h - padding
|
||||
self.items_per_page = math.floor(content_height / line_height)
|
||||
self.item_margin = self.item_margin + math.floor((content_height - self.items_per_page * line_height ) / self.items_per_page )
|
||||
self.pages = math.ceil(DB:selectCount() / self.items_per_page)
|
||||
self:setupItemHeight()
|
||||
self.main_content = VerticalGroup:new{}
|
||||
|
||||
self:_populateItems()
|
||||
@@ -889,6 +898,17 @@ function VocabularyBuilderWidget:init()
|
||||
}
|
||||
end
|
||||
|
||||
function VocabularyBuilderWidget:setupItemHeight()
|
||||
local item_height = Screen:scaleBySize(self.is_edit_mode and 54 or 72)
|
||||
self.item_height = item_height
|
||||
self.item_margin = math.floor(self.item_height / 8)
|
||||
local line_height = self.item_height + self.item_margin
|
||||
local content_height = self.dimen.h - self.title_bar:getHeight() - self.footer_height - Size.padding.large
|
||||
self.items_per_page = math.floor(content_height / line_height)
|
||||
self.item_margin = self.item_margin + math.floor((content_height - self.items_per_page * line_height ) / self.items_per_page )
|
||||
self.pages = math.ceil(DB:selectCount() / self.items_per_page)
|
||||
end
|
||||
|
||||
function VocabularyBuilderWidget:nextPage()
|
||||
local new_page = math.min(self.show_page+1, self.pages)
|
||||
if new_page > self.show_page then
|
||||
@@ -983,6 +1003,9 @@ function VocabularyBuilderWidget:_populateItems()
|
||||
self.footer_right:enableDisable(self.show_page < self.pages)
|
||||
self.footer_first_up:enableDisable(self.show_page > 1)
|
||||
self.footer_last_down:enableDisable(self.show_page < self.pages)
|
||||
if not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then
|
||||
self.selected = {x=1, y=1}
|
||||
end
|
||||
UIManager:setDirty(self, function()
|
||||
return "ui", self.dimen
|
||||
end)
|
||||
@@ -1019,6 +1042,12 @@ end
|
||||
|
||||
function VocabularyBuilderWidget:showMenu()
|
||||
UIManager:show(MenuDialog:new{
|
||||
is_edit_mode = self.is_edit_mode,
|
||||
edit_callback = function()
|
||||
self.is_edit_mode = not self.is_edit_mode
|
||||
self:setupItemHeight()
|
||||
self:_populateItems()
|
||||
end,
|
||||
clean_callback = function()
|
||||
self.item_table = {}
|
||||
self.pages = 0
|
||||
|
||||
Reference in New Issue
Block a user