Statistics: revamp settings, add calendar settings (#5867)

Also adds options to remove statistics for books
with low reading duration (to clean up stats for
books just quickly browsed and not yet read).
Also adds TextWidget:getFontSizeToFitHeight()
even if we ended up not using it.
pull/5872/head
poire-z 4 years ago committed by GitHub
parent 12e54a17b3
commit 95d18fe8d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -83,6 +83,8 @@ function DoubleSpinWidget:update()
value = self.left_value,
value_min = self.left_min,
value_max = self.left_max,
value_step = self.left_step,
value_hold_step = self.left_hold_step,
wrap = false,
update_callback = function() picker_update_callback() end,
}
@ -92,6 +94,8 @@ function DoubleSpinWidget:update()
value = self.right_value,
value_min = self.right_min,
value_max = self.right_max,
value_step = self.right_step,
value_hold_step = self.right_hold_step,
wrap = false,
update_callback = function() picker_update_callback() end,
}

@ -56,6 +56,29 @@ local TextWidget = Widget:new{
_xshaping = nil,
}
-- Helper function to be used before instantiating a TextWidget instance
-- (This is more precise than the one with the same name in TextBoxWidget,
-- as we use the real font metrics.)
function TextWidget:getFontSizeToFitHeight(font_name, height_px, padding)
-- Get a font size that would fit the text in height_px.
if not padding then
padding = self.padding -- (TextWidget default above: Size.padding.small)
end
-- We need to iterate (skip 1 early as font_size is always smaller
-- than font height)
local font_size = height_px
repeat
font_size = font_size - 1
if font_size <= 1 then
break
end
local face = Font:getFace(font_name, font_size)
local face_height = face.ftface:getHeightAndAscender()
face_height = math.ceil(face_height) + 2*padding
until face_height <= height_px
return font_size
end
function TextWidget:updateSize()
if self._updated then
return

@ -115,8 +115,8 @@ local CalendarDay = InputContainer:new{
is_future = false,
font_face = "xx_smallinfofont",
font_size = nil,
show_histo = true,
histo_height = nil,
nb_not_shown = nil,
}
function CalendarDay:init()
@ -154,15 +154,20 @@ function CalendarDay:init()
}
local inner_w = self.width - 2*self.border
local inner_h = self.height - 2*self.border
if not self.histo_height then
self.histo_height = inner_h / 3
if self.show_histo then
if not self.histo_height then
self.histo_height = inner_h / 3
end
self.histo_w = BottomContainer:new{
dimen = Geom:new{w = inner_w, h = inner_h},
HistogramWidget:new{
width = inner_w,
height = self.histo_height,
nb_items = 24,
ratios = self.ratio_per_hour,
}
}
end
self.histo_w = HistogramWidget:new{
width = inner_w,
height = self.histo_height,
nb_items = 24,
ratios = self.ratio_per_hour,
}
self[1] = FrameContainer:new{
padding = 0,
color = self.is_future and Blitbuffer.COLOR_GRAY or Blitbuffer.COLOR_BLACK,
@ -170,12 +175,10 @@ function CalendarDay:init()
width = self.width,
height = self.height,
OverlapGroup:new{
dimen = { w = inner_w },
self.daynum_w,
self.nb_not_shown_w,
BottomContainer:new{
dimen = Geom:new{w = inner_w, h = inner_h},
self.histo_w,
},
self.histo_w, -- nil if not show_histo
}
}
end
@ -203,6 +206,7 @@ local CalendarWeek = InputContainer:new{
day_padding = 0,
day_border = 0,
nb_book_spans = 0,
histo_shown = nil,
span_height = nil,
font_size = 0,
font_face = "xx_smallinfofont",
@ -299,17 +303,50 @@ function CalendarWeek:update()
-- Create and add BookSpans
local bspan_margin_h = Size.margin.tiny + self.day_border
local bspan_margin_v = Size.margin.tiny
local bspan_padding = Size.padding.tiny -- only used to compute the adequate font size
local bspan_padding_h = Size.padding.tiny
local bspan_border = Size.border.thin
local text_height = self.span_height - 2 * (bspan_margin_v + bspan_border + bspan_padding)
local inner_font_size = TextBoxWidget:getFontSizeToFitHeight(text_height, 1, 0)
-- We need a smaller font size than the one provided
local text_height = self.span_height - 2 * (bspan_margin_v + bspan_border)
-- We don't use any bspan_padding_v, we let that be handled by CenterContainer
-- and choosing an appropriate font size.
-- We use TextBoxWidget:getFontSizeToFitHeight() to get a fitting
-- font size. It's less precise than the TextWidget equivalent,
-- but it handles padding as 'em'.
-- Use a 1.3em line height
local inner_font_size = TextBoxWidget:getFontSizeToFitHeight(text_height, 1, 0.3)
-- If font size gets really small, get a larger one by using a smaller
-- line height: tall glyphs may bleed on the border, but we won't notice
-- at such small size, and we'll appreciate the readability.
-- (threshold values decided from visual testing)
if inner_font_size <= 12 then
inner_font_size = TextBoxWidget:getFontSizeToFitHeight(text_height, 1, 0.1)
elseif inner_font_size <= 15 then
inner_font_size = TextBoxWidget:getFontSizeToFitHeight(text_height, 1, 0.2)
end
-- But cap it to the day num font size
inner_font_size = math.min(inner_font_size, self.font_size)
local offset_y_fixup
if self.histo_shown then
-- No real y positionning needed, but push it a bit down
-- over histogram, as histograms rarely reach 100%, and
-- will be drawn last, so possibly over last book span if
-- really near 100%
offset_y_fixup = Size.margin.small
else
-- No histogram: ensure last book span bottom margin
-- is equal to bspan_margin_v for a nice fit
offset_y_fixup = self.height - self.span_height * (self.nb_book_spans + 1) - bspan_margin_v
end
for col, day_books in ipairs(self.days_books) do
for row, book in ipairs(day_books) do
if book and book.start_day == col then
local fgcolor, bgcolor = unpack(SPAN_COLORS[(book.id % #SPAN_COLORS)+1])
local offset_x = (col-1) * (self.day_width + self.day_padding)
local offset_y = row * self.span_height -- 1st real row used by day num
offset_y = offset_y + Size.margin.small -- push it a bit down, over histogram
offset_y = offset_y + offset_y_fixup
local width = book.span_days * self.day_width + self.day_padding * (book.span_days-1)
-- We use two FrameContainers, as (unlike HTML) a FrameContainer
-- draws the background color outside its borders, in the margins
@ -337,7 +374,7 @@ function CalendarWeek:update()
},
TextWidget:new{
text = BD.auto(book.title),
max_width = width - 2 * (bspan_margin_h + bspan_border + bspan_padding),
max_width = width - 2 * (bspan_margin_h + bspan_border + bspan_padding_h),
face = Font:getFace(self.font_face, inner_font_size),
padding = 0,
fgcolor = fgcolor,
@ -363,16 +400,19 @@ local CalendarView = InputContainer:new{
reader_statistics = nil,
monthTranslation = nil,
shortDayOfWeekTranslation = nil,
startDayOfWeek = 2, -- 2 = Monday, 1-7 = Sunday-Saturday
nbFutureMonths = 0, -- nb of future months to allow browsing
longDayOfWeekTranslation = nil,
start_day_of_week = 2, -- 2 = Monday, 1-7 = Sunday-Saturday
show_hourly_histogram = true,
browse_future_months = false,
nb_book_spans = 3,
font_face = "xx_smallinfofont",
title = "",
width = nil,
height = nil,
cur_month = nil,
weekdays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } -- in Lua wday order
-- (These do not need translations: they are the key into
-- the provided self.shortDayOfWeekTranslation)
-- (These do not need translations: they are the key into the provided
-- self.shortDayOfWeekTranslation and self.longDayOfWeekTranslation)
}
function CalendarView:init()
@ -419,15 +459,6 @@ function CalendarView:init()
if not self.cur_month then
self.cur_month = self.max_month
end
if self.nbFutureMonths > 0 then
local t = os.time({
year = self.max_month:sub(1,4),
month = self.max_month:sub(6),
day = 15,
})
t = t + 86400 * 30 * self.nbFutureMonths
self.max_month = os.date("%Y-%m", t)
end
-- group for page info
local chevron_left = "resources/icons/appbar.chevron.left.png"
@ -522,7 +553,7 @@ function CalendarView:init()
self.day_names = HorizontalGroup:new{}
for i = 0, 6 do
local dayname = TextWidget:new{
text = self.shortDayOfWeekTranslation[self.weekdays[(self.startDayOfWeek-1+i)%7 + 1]],
text = self.shortDayOfWeekTranslation[self.weekdays[(self.start_day_of_week-1+i)%7 + 1]],
face = Font:getFace("xx_smallinfofont"),
bold = true,
}
@ -544,9 +575,32 @@ function CalendarView:init()
- self.page_info:getSize().h - self.day_names:getSize().h
self.week_height = math.floor((available_height - 5*self.inner_padding) / 6)
self.day_border = Size.border.default
-- day num + nb_book_spans + histogram
self.span_height = math.ceil((self.week_height - 2*self.day_border) / (self.nb_book_spans + 2))
self.span_font_size = TextBoxWidget:getFontSizeToFitHeight(self.span_height, 1, 0.3)
if self.show_hourly_histogram then
-- day num + nb_book_spans + histogram: ceil() as histogram rarely
-- reaches 100% and is stuck to bottom
self.span_height = math.ceil((self.week_height - 2*self.day_border) / (self.nb_book_spans+2))
else
-- day num + nb_book_span: floor() to get some room for bottom padding
self.span_height = math.floor((self.week_height - 2*self.day_border) / (self.nb_book_spans+1))
end
-- Limit font size to 1/3 of available height, and so that
-- the day number and the +nb-not-shown do not overlap
local text_height = math.min(self.span_height, self.week_height/3)
self.span_font_size = TextBoxWidget:getFontSizeToFitHeight(text_height, 1, 0.3)
local day_inner_width = self.day_width - 2*self.day_border -2*self.inner_padding
while true do
local test_w = TextWidget:new{
text = " 30 + 99 ", -- we want this to be displayed in the available width
face = Font:getFace(self.font_face, self.span_font_size),
bold = true,
}
if test_w:getWidth() <= day_inner_width then
test_w:free()
break
end
self.span_font_size = self.span_font_size - 1
test_w:free()
end
self.main_content = VerticalGroup:new{}
self:_populateItems()
@ -593,9 +647,9 @@ function CalendarView:_populateItems()
-- Update footer
self.page_info_text:setText(self.cur_month)
self.page_info_left_chev:enableDisable(self.cur_month > self.min_month)
self.page_info_right_chev:enableDisable(self.cur_month < self.max_month)
self.page_info_right_chev:enableDisable(self.cur_month < self.max_month or self.browse_future_months)
self.page_info_first_chev:enableDisable(self.cur_month > self.min_month)
self.page_info_last_chev:enableDisable(self.cur_month < self.max_month)
self.page_info_last_chev:enableDisable(self.cur_month < self.max_month or self.browse_future_months)
local ratio_per_hour_by_day = self.reader_statistics:getReadingRatioPerHourByDay(self.cur_month)
local books_by_day = self.reader_statistics:getReadBookByDay(self.cur_month)
@ -612,7 +666,7 @@ function CalendarView:_populateItems()
if cur_date.month ~= this_month then
break
end
if not cur_week or cur_date.wday == self.startDayOfWeek then
if not cur_week or cur_date.wday == self.start_day_of_week then
if cur_week then
table.insert(self.main_content, VerticalSpan:new{ width = self.inner_padding })
end
@ -623,15 +677,17 @@ function CalendarView:_populateItems()
day_padding = self.inner_padding,
day_border = self.day_border,
nb_book_spans = self.nb_book_spans,
histo_shown = self.show_hourly_histogram,
span_height = self.span_height,
font_face = self.font_face,
font_size = self.span_font_size,
show_parent = self,
}
table.insert(self.weeks, cur_week)
table.insert(self.main_content, cur_week)
if cur_date.wday ~= self.startDayOfWeek then
if cur_date.wday ~= self.start_day_of_week then
-- Add fake days to fill week
local day = self.startDayOfWeek
local day = self.start_day_of_week
while day ~= cur_date.wday do
cur_week:addDay(CalendarDay:new{
filler = true,
@ -649,25 +705,28 @@ function CalendarView:_populateItems()
end
local day_s = os.date("%Y-%m-%d", cur_ts)
local day_text = string.format("%s (%s)", day_s,
self.shortDayOfWeekTranslation[self.weekdays[cur_date.wday]])
self.longDayOfWeekTranslation[self.weekdays[cur_date.wday]])
local day_ts = os.time({
year = cur_date.year,
month = cur_date.month,
day = cur_date.day,
hour = 0,
})
local is_future = day_s > today_s
cur_week:addDay(CalendarDay:new{
show_histo = self.show_hourly_histogram,
histo_height = self.span_height,
font_face = self.font_face,
font_size = self.span_font_size,
border = self.day_border,
is_future = day_s > today_s,
is_future = is_future,
daynum = cur_date.day,
height = self.week_height,
width = self.day_width,
ratio_per_hour = ratio_per_hour_by_day[day_s],
read_books = books_by_day[day_s],
show_parent = self,
callback = function()
callback = not is_future and function()
-- Just as ReaderStatistics:callbackDaily(), but without any window stacking
UIManager:show(KeyValuePage:new{
title = day_text,
@ -696,7 +755,7 @@ function CalendarView:nextMonth()
})
t = t + 86400 * 30 -- 30 days later
local next_month = os.date("%Y-%m", t)
if next_month <= self.max_month then
if self.browse_future_months or next_month <= self.max_month then
self.cur_month = next_month
self:_populateItems()
end

@ -6,7 +6,6 @@ local Device = require("device")
local DocSettings = require("docsettings")
local InfoMessage = require("ui/widget/infomessage")
local KeyValuePage = require("ui/widget/keyvaluepage")
local MultiInputDialog = require("ui/widget/multiinputdialog")
local ReaderFooter = require("apps/reader/modules/readerfooter")
local ReaderProgress = require("readerprogress")
local ReadHistory = require("readhistory")
@ -29,18 +28,24 @@ local db_location = DataStorage:getSettingsDir() .. "/statistics.sqlite3"
local PAGE_INSERT = 50
local DEFAULT_MIN_READ_SEC = 5
local DEFAULT_MAX_READ_SEC = 120
local DEFAULT_CALENDAR_START_DAY_OF_WEEK = 2 -- Monday
local DEFAULT_CALENDAR_NB_BOOK_SPANS = 3
local ReaderStatistics = Widget:extend{
name = "statistics",
page_min_read_sec = DEFAULT_MIN_READ_SEC,
page_max_read_sec = DEFAULT_MAX_READ_SEC,
calendar_start_day_of_week = DEFAULT_CALENDAR_START_DAY_OF_WEEK,
calendar_nb_book_spans = DEFAULT_CALENDAR_NB_BOOK_SPANS,
calendar_show_histogram = true,
calendar_browse_future_months = false,
start_current_period = 0,
curr_page = 0,
id_curr_book = nil,
curr_total_time = 0,
curr_total_pages = 0,
is_enabled = nil,
convert_to_db = nil,
convert_to_db = nil, -- true when migration to DB has been done
total_read_pages = 0,
total_read_time = 0,
avg_time = nil,
@ -59,6 +64,8 @@ local ReaderStatistics = Widget:extend{
},
}
local weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } -- in Lua wday order
local shortDayOfWeekTranslation = {
["Mon"] = _("Mon"),
["Tue"] = _("Tue"),
@ -69,6 +76,16 @@ local shortDayOfWeekTranslation = {
["Sun"] = _("Sun"),
}
local longDayOfWeekTranslation = {
["Mon"] = _("Monday"),
["Tue"] = _("Tuesday"),
["Wed"] = _("Wednesday"),
["Thu"] = _("Thursday"),
["Fri"] = _("Friday"),
["Sat"] = _("Saturday"),
["Sun"] = _("Sunday"),
}
local monthTranslation = {
["January"] = _("January"),
["February"] = _("February"),
@ -97,6 +114,10 @@ function ReaderStatistics:init()
local settings = G_reader_settings:readSetting("statistics") or {}
self.page_min_read_sec = tonumber(settings.min_sec)
self.page_max_read_sec = tonumber(settings.max_sec)
self.calendar_start_day_of_week = settings.calendar_start_day_of_week
self.calendar_nb_book_spans = settings.calendar_nb_book_spans
self.calendar_show_histogram = settings.calendar_show_histogram
self.calendar_browse_future_months = settings.calendar_browse_future_months
self.is_enabled = not (settings.is_enabled == false)
self.convert_to_db = settings.convert_to_db
self.ui.menu:registerToMainMenu(self)
@ -228,7 +249,7 @@ end
function ReaderStatistics:checkInitDatabase()
local conn = SQ3.open(db_location)
if self.convert_to_db then -- if conversion to sqlite was doing earlier
if self.convert_to_db then -- if conversion to sqlite DB has already been done
if not conn:exec("pragma table_info('book');") then
UIManager:show(ConfirmBox:new{
text = T(_([[
@ -251,7 +272,7 @@ Do you want to create an empty database?
end,
})
end
else -- first time convertion to sqlite database
else -- Migrate stats for books in history from metadata.lua to sqlite database
self.convert_to_db = true
if not conn:exec("pragma table_info('book');") then
local filename_first_history, quickstart_filename, __
@ -671,48 +692,6 @@ function ReaderStatistics:getStatisticEnabledMenuItem()
}
end
function ReaderStatistics:updateSettings()
self.settings_dialog = MultiInputDialog:new {
title = _("Statistics settings"),
fields = {
{
text = self.page_min_read_sec,
description = T(_("Min seconds, default is %1"), DEFAULT_MIN_READ_SEC),
input_type = "number",
},
{
text = self.page_max_read_sec,
description = T(_("Max seconds, default is %1"), DEFAULT_MAX_READ_SEC),
input_type = "number",
},
},
buttons = {
{
{
text = _("Cancel"),
callback = function()
self.settings_dialog:onClose()
UIManager:close(self.settings_dialog)
end
},
{
text = _("Apply"),
callback = function()
self:saveSettings(MultiInputDialog:getFields())
self.settings_dialog:onClose()
UIManager:close(self.settings_dialog)
end
},
},
},
width = Screen:getWidth() * 0.95,
height = Screen:getHeight() * 0.2,
input_type = "number",
}
UIManager:show(self.settings_dialog)
self.settings_dialog:onShowKeyboard()
end
function ReaderStatistics:addToMainMenu(menu_items)
menu_items.statistics = {
text = _("Reading statistics"),
@ -720,15 +699,130 @@ function ReaderStatistics:addToMainMenu(menu_items)
self:getStatisticEnabledMenuItem(),
{
text = _("Settings"),
keep_menu_open = true,
callback = function() self:updateSettings() end,
sub_item_table = {
{
text_func = function()
return T(_("Read page duration limits: %1 s / %2 s"),
self.page_min_read_sec, self.page_max_read_sec)
end,
callback = function(touchmenu_instance)
local DoubleSpinWidget = require("/ui/widget/doublespinwidget")
local durations_widget
durations_widget = DoubleSpinWidget:new{
left_text = _("Min"),
left_value = self.page_min_read_sec,
left_default = DEFAULT_MIN_READ_SEC,
left_min = 3,
left_max = 120,
left_step = 1,
left_hold_step = 10,
right_text = _("Max"),
right_value = self.page_max_read_sec,
right_default = DEFAULT_MAX_READ_SEC,
right_min = 10,
right_max = 7200,
right_step = 10,
right_hold_step = 60,
default_values = true,
default_text = _("Use defaults"),
title_text = _("Read page duration limits"),
info_text = _([[
Set min and max time spent (in seconds) on a page for it to be counted as read in statistics.
The min value ensures pages you quickly browse and skip are not included.
The max value ensures a page you stay on for a long time (because you fell asleep or went away) will be included, but with a duration capped to this specified max value.]]),
callback = function(min, max)
if not min then min = DEFAULT_MIN_READ_SEC end
if not max then max = DEFAULT_MAX_READ_SEC end
if min > max then
min, max = max, min
end
self.page_min_read_sec = min
self.page_max_read_sec = max
self:saveSettings()
UIManager:close(durations_widget)
touchmenu_instance:updateItems()
end,
}
UIManager:show(durations_widget)
end,
keep_menu_open = true,
separator = true,
},
{
text_func = function()
return T(_("Calendar weeks start on %1"),
longDayOfWeekTranslation[weekDays[self.calendar_start_day_of_week]])
end,
sub_item_table = {
{ -- Friday (Bangladesh and Maldives)
text = longDayOfWeekTranslation[weekDays[6]],
checked_func = function() return self.calendar_start_day_of_week == 6 end,
callback = function() self.calendar_start_day_of_week = 6 end
},
{ -- Saturday (some Middle East countries)
text = longDayOfWeekTranslation[weekDays[7]],
checked_func = function() return self.calendar_start_day_of_week == 7 end,
callback = function() self.calendar_start_day_of_week = 7 end
},
{ -- Sunday
text = longDayOfWeekTranslation[weekDays[1]],
checked_func = function() return self.calendar_start_day_of_week == 1 end,
callback = function() self.calendar_start_day_of_week = 1 end
},
{ -- Monday
text = longDayOfWeekTranslation[weekDays[2]],
checked_func = function() return self.calendar_start_day_of_week == 2 end,
callback = function() self.calendar_start_day_of_week = 2 end
},
},
},
{
text_func = function()
return T(_("Books per calendar day: %1"), self.calendar_nb_book_spans)
end,
callback = function(touchmenu_instance)
local SpinWidget = require("ui/widget/spinwidget")
UIManager:show(SpinWidget:new{
width = Screen:getWidth() * 0.6,
value = self.calendar_nb_book_spans,
value_min = 1,
value_max = 5,
ok_text = _("Set"),
title_text = _("Books per calendar day"),
text = _("Set the max number of book spans to show for a day"),
callback = function(spin)
self.calendar_nb_book_spans = spin.value
touchmenu_instance:updateItems()
end,
extra_text = _("Use default"),
extra_callback = function()
self.calendar_nb_book_spans = DEFAULT_CALENDAR_NB_BOOK_SPANS
touchmenu_instance:updateItems()
end
})
end,
keep_menu_open = true,
},
{
text = _("Show hourly histogram in calendar days"),
checked_func = function() return self.calendar_show_histogram end,
callback = function()
self.calendar_show_histogram = not self.calendar_show_histogram
end,
},
{
text = _("Allow browsing coming months"),
checked_func = function() return self.calendar_browse_future_months end,
callback = function()
self.calendar_browse_future_months = not self.calendar_browse_future_months
end,
},
},
},
{
text = _("Reset book statistics"),
keep_menu_open = true,
callback = function()
self:resetBook()
end
text = _("Reset statistics"),
sub_item_table = self:genResetBookSubItemTable(),
separator = true,
},
{
text = _("Current book"),
@ -779,6 +873,11 @@ function ReaderStatistics:addToMainMenu(menu_items)
reader_statistics = self,
monthTranslation = monthTranslation,
shortDayOfWeekTranslation = shortDayOfWeekTranslation,
longDayOfWeekTranslation = longDayOfWeekTranslation,
start_day_of_week = self.calendar_start_day_of_week,
nb_book_spans = self.calendar_nb_book_spans,
show_hourly_histogram = self.calendar_show_histogram,
browse_future_months = self.calendar_browse_future_months,
})
end,
},
@ -1580,6 +1679,32 @@ function ReaderStatistics:getTotalStats()
return T(_("Total hours read %1"), util.secondsToClock(total_books_time, false)), total_stats
end
function ReaderStatistics:genResetBookSubItemTable()
local sub_item_table = {}
table.insert(sub_item_table, {
text = _("Reset statistics per book"),
keep_menu_open = true,
callback = function()
self:resetBook()
end,
separator = true,
})
local reset_minutes = { 1, 5, 15, 30, 60 }
for _, minutes in ipairs(reset_minutes) do
local text = T(N_("Reset stats for books read for < 1 m",
"Reset stats for books read for < %1 m",
minutes), minutes)
table.insert(sub_item_table, {
text = text,
keep_menu_open = true,
callback = function()
self:deleteBooksByTotalDuration(minutes)
end,
})
end
return sub_item_table
end
function ReaderStatistics:resetBook()
local total_stats = {}
local kv_reset_book
@ -1675,6 +1800,56 @@ function ReaderStatistics:deleteBook(id_book)
conn:close()
end
function ReaderStatistics:deleteBooksByTotalDuration(max_total_duration_mn)
local max_total_duration_sec = max_total_duration_mn * 60
UIManager:show(ConfirmBox:new{
text = T(N_("Permanently remove statistics for books read for less than 1 minute?",
"Permanently remove statistics for books read for less than %1 minutes?",
max_total_duration_mn), max_total_duration_mn),
ok_text = _("Remove"),
ok_callback = function()
local conn = SQ3.open(db_location)
local sql_stmt = [[
DELETE from page_stat
WHERE id_book in (
select id from book where id != ? and (total_read_time is NULL or total_read_time < ?)
)
]]
local stmt = conn:prepare(sql_stmt)
stmt:reset():bind(self.id_curr_book, max_total_duration_sec):step()
sql_stmt = [[
DELETE from book
WHERE id != ? and (total_read_time is NULL or total_read_time < ?)
]]
stmt = conn:prepare(sql_stmt)
stmt:reset():bind(self.id_curr_book, max_total_duration_sec):step()
stmt:close()
-- Get nb of deleted books
sql_stmt = [[
SELECT changes()
]]
local nb_deleted = conn:rowexec(sql_stmt)
nb_deleted = nb_deleted and tonumber(nb_deleted) or 0
if max_total_duration_mn >= 30 and nb_deleted >= 10 then
-- Do a VACUUM to reduce db size (but not worth doing if not much was removed)
conn:exec("PRAGMA temp_store = 2") -- use memory for temp files
local ok, errmsg = pcall(conn.exec, conn, "VACUUM") -- this may take some time
if not ok then
logger.warn("Failed compacting statistics database:", errmsg)
end
end
conn:close()
UIManager:show(InfoMessage:new{
text = nb_deleted > 0 and T(N_("Statistics for 1 book removed.",
"Statistics for %1 books removed.",
nb_deleted), nb_deleted)
or T(_("No statistics removed."))
})
end,
})
end
function ReaderStatistics:onPosUpdate(pos, pageno)
if self.curr_page ~= pageno then
self:onPageUpdate(pageno)
@ -1777,17 +1952,16 @@ function ReaderStatistics:onResume()
self.pages_stats[self.start_current_period] = self.curr_page
end
function ReaderStatistics:saveSettings(fields)
if fields then
self.page_min_read_sec = tonumber(fields[1])
self.page_max_read_sec = tonumber(fields[2])
end
function ReaderStatistics:saveSettings()
local settings = {
min_sec = self.page_min_read_sec,
max_sec = self.page_max_read_sec,
is_enabled = self.is_enabled,
convert_to_db = self.convert_to_db
convert_to_db = self.convert_to_db,
calendar_start_day_of_week = self.calendar_start_day_of_week,
calendar_nb_book_spans = self.calendar_nb_book_spans,
calendar_show_histogram = self.calendar_show_histogram,
calendar_browse_future_months = self.calendar_browse_future_months,
}
G_reader_settings:saveSetting("statistics", settings)
end

Loading…
Cancel
Save