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)
|
function VocabularyBuilder:insertOrUpdate(entry)
|
||||||
local conn = SQ3.open(db_location)
|
local conn = SQ3.open(db_location)
|
||||||
|
local stmt = conn:prepare([[INSERT INTO vocabulary (word, book_title, create_time, due_time)
|
||||||
conn:exec(string.format([[INSERT INTO vocabulary (word, book_title, create_time, due_time)
|
VALUES (?, ?, ?, ?)
|
||||||
VALUES ('%s', '%s', %d, %d)
|
|
||||||
ON CONFLICT(word) DO UPDATE SET book_title = excluded.book_title,
|
ON CONFLICT(word) DO UPDATE SET book_title = excluded.book_title,
|
||||||
create_time = excluded.create_time,
|
create_time = excluded.create_time,
|
||||||
review_count = MAX(review_count-1, 0),
|
review_count = MAX(review_count-1, 0),
|
||||||
due_time = %d;
|
due_time = ?;]])
|
||||||
]], entry.word, entry.book_title, entry.time, entry.time+300, entry.time+300))
|
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;"))
|
self.count = tonumber(conn:rowexec("SELECT count(0) from vocabulary;"))
|
||||||
conn:close()
|
conn:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
function VocabularyBuilder:remove(item)
|
function VocabularyBuilder:remove(item)
|
||||||
local conn = SQ3.open(db_location)
|
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
|
self.count = self.count - 1
|
||||||
conn:close()
|
conn:close()
|
||||||
end
|
end
|
||||||
@@ -229,13 +234,6 @@ function VocabularyBuilder:resetProgress()
|
|||||||
conn:close()
|
conn:close()
|
||||||
end
|
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()
|
function VocabularyBuilder:purge()
|
||||||
local conn = SQ3.open(db_location)
|
local conn = SQ3.open(db_location)
|
||||||
conn:exec("DELETE FROM vocabulary;")
|
conn:exec("DELETE FROM vocabulary;")
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ Menu dialogue widget
|
|||||||
--]]--
|
--]]--
|
||||||
local MenuDialog = FocusManager:new{
|
local MenuDialog = FocusManager:new{
|
||||||
padding = Size.padding.fullscreen,
|
padding = Size.padding.fullscreen,
|
||||||
|
is_edit_mode = false,
|
||||||
|
edit_callback = nil,
|
||||||
tap_close_callback = nil,
|
tap_close_callback = nil,
|
||||||
clean_callback = nil,
|
clean_callback = nil,
|
||||||
reset_callback = nil,
|
reset_callback = nil,
|
||||||
@@ -99,6 +101,14 @@ function MenuDialog:init()
|
|||||||
switch:setPosition(settings.enabled and 2 or 1)
|
switch:setPosition(settings.enabled and 2 or 1)
|
||||||
self:mergeLayoutInVertical(switch)
|
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 = {
|
local reset_button = {
|
||||||
text = _("Reset all progress"),
|
text = _("Reset all progress"),
|
||||||
callback = function()
|
callback = function()
|
||||||
@@ -132,6 +142,7 @@ function MenuDialog:init()
|
|||||||
local buttons = ButtonTable:new{
|
local buttons = ButtonTable:new{
|
||||||
width = width,
|
width = width,
|
||||||
buttons = {
|
buttons = {
|
||||||
|
{edit_button},
|
||||||
{reset_button},
|
{reset_button},
|
||||||
{clean_button}
|
{clean_button}
|
||||||
},
|
},
|
||||||
@@ -451,7 +462,7 @@ function VocabItemWidget:initItemWidget()
|
|||||||
|
|
||||||
table.insert(self.layout, word_widget)
|
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{
|
self.more_button = Button:new{
|
||||||
text = "⋮",
|
text = "⋮",
|
||||||
padding = Size.padding.button,
|
padding = Size.padding.button,
|
||||||
@@ -477,7 +488,7 @@ function VocabItemWidget:initItemWidget()
|
|||||||
|
|
||||||
local right_side_width
|
local right_side_width
|
||||||
local right_widget
|
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
|
right_side_width = review_button_width * 2 + Size.padding.large * 2 + ellipsis_button_width
|
||||||
|
|
||||||
self.forgot_button = Button:new{
|
self.forgot_button = Button:new{
|
||||||
@@ -690,6 +701,9 @@ function VocabItemWidget:onGotIt()
|
|||||||
self.item.got_it_callback(self.item)
|
self.item.got_it_callback(self.item)
|
||||||
self.item.is_dim = true
|
self.item.is_dim = true
|
||||||
self:initItemWidget()
|
self:initItemWidget()
|
||||||
|
if self.show_parent.selected.x == 3 then
|
||||||
|
self.show_parent.selected.x = 1
|
||||||
|
end
|
||||||
UIManager:setDirty(self.show_parent, function()
|
UIManager:setDirty(self.show_parent, function()
|
||||||
return "ui", self[1].dimen end)
|
return "ui", self[1].dimen end)
|
||||||
end
|
end
|
||||||
@@ -718,6 +732,7 @@ local VocabularyBuilderWidget = FocusManager:new{
|
|||||||
show_page = 1,
|
show_page = 1,
|
||||||
-- table of items
|
-- table of items
|
||||||
item_table = nil, -- mandatory (array)
|
item_table = nil, -- mandatory (array)
|
||||||
|
is_edit_mode = false,
|
||||||
callback = nil,
|
callback = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,7 +761,6 @@ function VocabularyBuilderWidget:init()
|
|||||||
self.item_width = self.dimen.w - 2 * padding
|
self.item_width = self.dimen.w - 2 * padding
|
||||||
self.footer_center_width = math.floor(self.width_widget * 32 / 100)
|
self.footer_center_width = math.floor(self.width_widget * 32 / 100)
|
||||||
self.footer_button_width = math.floor(self.width_widget * 12 / 100)
|
self.footer_button_width = math.floor(self.width_widget * 12 / 100)
|
||||||
self.item_height = Screen:scaleBySize(72)
|
|
||||||
-- group for footer
|
-- group for footer
|
||||||
local chevron_left = "chevron.left"
|
local chevron_left = "chevron.left"
|
||||||
local chevron_right = "chevron.right"
|
local chevron_right = "chevron.right"
|
||||||
@@ -834,6 +848,7 @@ function VocabularyBuilderWidget:init()
|
|||||||
bottom_line,
|
bottom_line,
|
||||||
self.page_info,
|
self.page_info,
|
||||||
}
|
}
|
||||||
|
self.footer_height = vertical_footer:getSize().h
|
||||||
local footer = BottomContainer:new{
|
local footer = BottomContainer:new{
|
||||||
dimen = self.dimen:copy(),
|
dimen = self.dimen:copy(),
|
||||||
vertical_footer,
|
vertical_footer,
|
||||||
@@ -853,13 +868,7 @@ function VocabularyBuilderWidget:init()
|
|||||||
show_parent = self,
|
show_parent = self,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- setup main content
|
self:setupItemHeight()
|
||||||
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.main_content = VerticalGroup:new{}
|
self.main_content = VerticalGroup:new{}
|
||||||
|
|
||||||
self:_populateItems()
|
self:_populateItems()
|
||||||
@@ -889,6 +898,17 @@ function VocabularyBuilderWidget:init()
|
|||||||
}
|
}
|
||||||
end
|
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()
|
function VocabularyBuilderWidget:nextPage()
|
||||||
local new_page = math.min(self.show_page+1, self.pages)
|
local new_page = math.min(self.show_page+1, self.pages)
|
||||||
if new_page > self.show_page then
|
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_right:enableDisable(self.show_page < self.pages)
|
||||||
self.footer_first_up:enableDisable(self.show_page > 1)
|
self.footer_first_up:enableDisable(self.show_page > 1)
|
||||||
self.footer_last_down:enableDisable(self.show_page < self.pages)
|
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()
|
UIManager:setDirty(self, function()
|
||||||
return "ui", self.dimen
|
return "ui", self.dimen
|
||||||
end)
|
end)
|
||||||
@@ -1019,6 +1042,12 @@ end
|
|||||||
|
|
||||||
function VocabularyBuilderWidget:showMenu()
|
function VocabularyBuilderWidget:showMenu()
|
||||||
UIManager:show(MenuDialog:new{
|
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()
|
clean_callback = function()
|
||||||
self.item_table = {}
|
self.item_table = {}
|
||||||
self.pages = 0
|
self.pages = 0
|
||||||
|
|||||||
Reference in New Issue
Block a user