Skip to content

Commit 40edca0

Browse files
committed
Use live statistics state for status updates
1 parent 7b4ca6c commit 40edca0

2 files changed

Lines changed: 186 additions & 7 deletions

File tree

main.lua

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,24 @@ function StatusStats:getStatisticsPlugin()
116116
return nil
117117
end
118118

119-
function StatusStats:getStatisticsPair(method_name)
120-
local statistics = self:getStatisticsPlugin()
119+
function StatusStats:getNowTimestamp()
120+
return os.time()
121+
end
122+
123+
function StatusStats:getBaseStatisticsPair(statistics, method_name)
121124
if not (statistics and statistics[method_name]) then
122-
return nil
125+
return {
126+
time = 0,
127+
pages = 0,
128+
}
123129
end
124130

125131
local ok, duration, pages = pcall(statistics[method_name], statistics)
126132
if not ok then
127-
return nil
133+
return {
134+
time = 0,
135+
pages = 0,
136+
}
128137
end
129138

130139
return {
@@ -133,12 +142,111 @@ function StatusStats:getStatisticsPair(method_name)
133142
}
134143
end
135144

145+
function StatusStats:getLiveTupleDurationSince(statistics, page, data_list, tuple_index, boundary_time)
146+
local tuple = data_list and data_list[tuple_index]
147+
if type(tuple) ~= "table" then
148+
return 0
149+
end
150+
151+
local start_time = tonumber(tuple[1])
152+
local stored_duration = tonumber(tuple[2]) or 0
153+
if not start_time then
154+
return 0
155+
end
156+
157+
local effective_duration = math.max(stored_duration, 0)
158+
local is_active_tuple = statistics.curr_page == page
159+
and tuple_index == #data_list
160+
and not statistics._reading_paused_ts
161+
162+
if is_active_tuple then
163+
local settings = statistics.settings or {}
164+
local min_sec = tonumber(settings.min_sec) or 0
165+
local max_sec = tonumber(settings.max_sec) or math.huge
166+
local elapsed = math.max(self:getNowTimestamp() - start_time, 0)
167+
168+
if elapsed >= min_sec then
169+
effective_duration = math.max(effective_duration, math.min(elapsed, max_sec))
170+
end
171+
end
172+
173+
if effective_duration <= 0 then
174+
return 0
175+
end
176+
177+
boundary_time = tonumber(boundary_time) or 0
178+
if start_time >= boundary_time then
179+
return effective_duration
180+
end
181+
182+
local end_time = start_time + effective_duration
183+
if end_time <= boundary_time then
184+
return 0
185+
end
186+
187+
return end_time - boundary_time
188+
end
189+
190+
function StatusStats:getLiveStatisticsPair(statistics, boundary_time)
191+
if not (statistics and type(statistics.page_stat) == "table") then
192+
return {
193+
time = 0,
194+
pages = 0,
195+
}
196+
end
197+
198+
local live_duration = 0
199+
local live_pages = 0
200+
201+
for page, data_list in pairs(statistics.page_stat) do
202+
if type(data_list) == "table" then
203+
local page_duration = 0
204+
205+
for tuple_index = 1, #data_list do
206+
page_duration = page_duration
207+
+ self:getLiveTupleDurationSince(statistics, page, data_list, tuple_index, boundary_time)
208+
end
209+
210+
if page_duration > 0 then
211+
live_duration = live_duration + page_duration
212+
live_pages = live_pages + 1
213+
end
214+
end
215+
end
216+
217+
return {
218+
time = live_duration,
219+
pages = live_pages,
220+
}
221+
end
222+
223+
function StatusStats:getStatisticsPair(method_name, boundary_time)
224+
local statistics = self:getStatisticsPlugin()
225+
if not statistics then
226+
return nil
227+
end
228+
229+
local persisted = self:getBaseStatisticsPair(statistics, method_name)
230+
local live = self:getLiveStatisticsPair(statistics, boundary_time)
231+
232+
return {
233+
time = persisted.time + live.time,
234+
pages = persisted.pages + live.pages,
235+
}
236+
end
237+
136238
function StatusStats:getTodayStats()
137-
return self:getStatisticsPair("getTodayBookStats")
239+
local now_stamp = self:getNowTimestamp()
240+
local now_t = os.date("*t", now_stamp)
241+
local from_begin_day = now_t.hour * 3600 + now_t.min * 60 + now_t.sec
242+
local start_today_time = now_stamp - from_begin_day
243+
return self:getStatisticsPair("getTodayBookStats", start_today_time)
138244
end
139245

140246
function StatusStats:getSessionStats()
141-
return self:getStatisticsPair("getCurrentBookStats")
247+
local statistics = self:getStatisticsPlugin()
248+
local boundary_time = statistics and statistics.start_current_period or self:getNowTimestamp()
249+
return self:getStatisticsPair("getCurrentBookStats", boundary_time)
142250
end
143251

144252
function StatusStats:formatDuration(seconds)

tests/statusstats_spec.lua

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@ local function assertTrue(value, message)
1212
end
1313
end
1414

15+
local real_os_time = os.time
16+
local fake_now
17+
18+
os.time = function(value)
19+
if value ~= nil then
20+
return real_os_time(value)
21+
end
22+
return fake_now or real_os_time()
23+
end
24+
25+
local function setFakeNow(value)
26+
fake_now = value
27+
end
28+
1529
local ui_manager_state = {
1630
shown = {},
1731
unscheduled = {},
@@ -185,6 +199,14 @@ local function newPlugin(settings, stats)
185199
getTodayBookStats = function()
186200
return stats.today.time, stats.today.pages
187201
end,
202+
page_stat = stats.page_stat,
203+
curr_page = stats.curr_page,
204+
start_current_period = stats.start_current_period,
205+
_reading_paused_ts = stats.reading_paused_ts,
206+
settings = stats.statistics_settings or {
207+
min_sec = 5,
208+
max_sec = 120,
209+
},
188210
},
189211
},
190212
}, { __index = StatusStats })
@@ -297,6 +319,42 @@ assertTrue(menu_text:find("Today", 1, true) ~= nil, "today menu should exist")
297319
assertTrue(menu_text:find("Label style", 1, true) == nil, "label style menu should be removed")
298320
assertTrue(menu_text:find("Book stats", 1, true) == nil, "book stats menu should be removed")
299321

322+
setFakeNow(1130)
323+
local live_session_plugin = newPlugin({
324+
session = {
325+
time = true,
326+
pages = true,
327+
},
328+
}, {
329+
session = {
330+
time = 0,
331+
pages = 0,
332+
},
333+
today = {
334+
time = 0,
335+
pages = 0,
336+
},
337+
page_stat = {
338+
[1] = {
339+
{ 1000, 30 },
340+
},
341+
[2] = {
342+
{ 1100, 0 },
343+
},
344+
},
345+
curr_page = 2,
346+
start_current_period = 900,
347+
statistics_settings = {
348+
min_sec = 5,
349+
max_sec = 3600,
350+
},
351+
})
352+
353+
local live_session_stats = live_session_plugin:getSessionStats()
354+
assertEquals(live_session_stats.time, 60, "session stats should include live in-memory reading time")
355+
assertEquals(live_session_stats.pages, 2, "session stats should include live in-memory read pages")
356+
357+
setFakeNow(1200)
300358
local time_refresh_plugin = newPlugin({
301359
show_value_in_footer = true,
302360
session = {
@@ -305,13 +363,24 @@ local time_refresh_plugin = newPlugin({
305363
},
306364
}, {
307365
session = {
308-
time = 125,
366+
time = 0,
309367
pages = 0,
310368
},
311369
today = {
312370
time = 0,
313371
pages = 0,
314372
},
373+
page_stat = {
374+
[7] = {
375+
{ 1075, 0 },
376+
},
377+
},
378+
curr_page = 7,
379+
start_current_period = 1000,
380+
statistics_settings = {
381+
min_sec = 5,
382+
max_sec = 3600,
383+
},
315384
})
316385

317386
time_refresh_plugin:onReaderReady()
@@ -442,4 +511,6 @@ assertTrue(restore_footer_plugin.ui.view.footer.settings.all_at_once, "disabling
442511
assertEquals(restore_footer_plugin.ui.view.footer.mode, "normal", "disabling footer stats should restore the previous footer mode")
443512
assertEquals(restore_footer_plugin.ui.view.footer.remove_calls, 1, "disabling footer stats should remove footer content once")
444513

514+
os.time = real_os_time
515+
445516
print("statusstats smoke tests passed")

0 commit comments

Comments
 (0)