2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/plugins/statistics.koplugin/calendarview.lua
NiLuJe 525b1957b9
[RFC] Pagination UI shenanigans (#7335)
* Menu/KeyValuePage/ReaderGoTo: Unify the dialogs. (Generally, "Enter page number" as title, and "Go to page" as OK button).
* Allow *tapping* on pagination buttons, too. Added spacers around the text to accommodate for that.
* Disable input handlers when <= 1 pages, while still printing the label in black.
* Always display both the label and the chevrons, even on single page content. (Menu being an exception, because it can handle showing no content at all, in which case we hide the chevrons).
* KVP: Tweak the pagination buttons layout in order to have consistent centering, regardless of whether the return arrow is enabled or not. (Also, match Menu's layout, more or less).
* Menu: Minor layout tweaks to follow the KVP tweaks above. Fixes, among possibly other things, buttons in (non-FM) "List" menus overlapping the final entry (e.g., OPDS), and popout menus with a border being misaligned (e.g., Calibre, Find a file).
* CalendarView: Minor layout tweaks to follow the KVP tweaks. Ensures the pagination buttons are laid out in the same way as everywhere else (they used to be a wee bit higher).
2021-02-25 05:15:23 +01:00

835 lines
29 KiB
Lua

local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local BottomContainer = require("ui/widget/container/bottomcontainer")
local Button = require("ui/widget/button")
local CenterContainer = require("ui/widget/container/centercontainer")
local CloseButton = require("ui/widget/closebutton")
local Device = require("device")
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local InputContainer = require("ui/widget/container/inputcontainer")
local KeyValuePage = require("ui/widget/keyvaluepage")
local LeftContainer = require("ui/widget/container/leftcontainer")
local Math = require("optmath")
local OverlapGroup = require("ui/widget/overlapgroup")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local Widget = require("ui/widget/widget")
local Input = Device.input
local Screen = Device.screen
local _ = require("gettext")
local CalendarTitle = VerticalGroup:new{
calendar_view = nil,
title = "",
tface = Font:getFace("tfont"),
align = "left",
}
function CalendarTitle:init()
self.close_button = CloseButton:new{ window = self }
local btn_width = self.close_button:getSize().w
self.text_w = TextWidget:new{
text = self.title,
max_width = self.width - btn_width,
face = self.tface,
}
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
self.text_w,
self.close_button,
})
table.insert(self, VerticalSpan:new{ width = Size.span.vertical_large })
end
function CalendarTitle:setTitle(title)
self.text_w:setText(title)
end
function CalendarTitle:onClose()
self.calendar_view:onClose()
return true
end
local HistogramWidget = Widget:new{
width = nil,
height = nil,
color = Blitbuffer.COLOR_BLACK,
nb_items = nil,
ratios = nil, -- table of 1...nb_items items, each with (0 <= value <= 1)
}
function HistogramWidget:init()
self.dimen = Geom:new{w = self.width, h = self.height}
local item_width = math.floor(self.width / self.nb_items)
local nb_item_width_add1 = self.width - self.nb_items * item_width
local nb_item_width_add1_mod = math.floor(self.nb_items/nb_item_width_add1)
self.item_widths = {}
for n = 1, self.nb_items do
local w = item_width
if nb_item_width_add1 > 0 and n % nb_item_width_add1_mod == 0 then
w = w + 1
nb_item_width_add1 = nb_item_width_add1 - 1
end
table.insert(self.item_widths, w)
end
if BD.mirroredUILayout() then
self.do_mirror = true
end
end
function HistogramWidget:paintTo(bb, x, y)
local i_x = 0
for n = 1, self.nb_items do
if self.do_mirror then
n = self.nb_items - n + 1
end
local i_w = self.item_widths[n]
local ratio = self.ratios and self.ratios[n] or 0
local i_h = Math.round(ratio * self.height)
if i_h == 0 and ratio > 0 then -- show at least 1px
i_h = 1
end
local i_y = self.height - i_h
if i_h > 0 then
bb:paintRect(x + i_x, y + i_y, i_w, i_h, self.color)
end
i_x = i_x + i_w
end
end
local CalendarDay = InputContainer:new{
daynum = nil,
ratio_per_hour = nil,
filler = false,
width = nil,
height = nil,
border = 0,
is_future = false,
font_face = "xx_smallinfofont",
font_size = nil,
show_histo = true,
histo_height = nil,
}
function CalendarDay:init()
self.dimen = Geom:new{w = self.width, h = self.height}
if self.filler then
return
end
if self.callback and Device:isTouchDevice() then
self.ges_events.Tap = {
GestureRange:new{
ges = "tap",
range = self.dimen,
}
}
self.ges_events.Hold = {
GestureRange:new{
ges = "hold",
range = self.dimen,
}
}
end
self.daynum_w = TextWidget:new{
text = " " .. tostring(self.daynum),
face = Font:getFace(self.font_face, self.font_size),
fgcolor = self.is_future and Blitbuffer.COLOR_GRAY or Blitbuffer.COLOR_BLACK,
padding = 0,
bold = true,
}
self.nb_not_shown_w = TextWidget:new{
text = "",
face = Font:getFace(self.font_face, self.font_size - 1),
fgcolor = Blitbuffer.COLOR_DARK_GRAY,
overlap_align = "right",
}
local inner_w = self.width - 2*self.border
local inner_h = self.height - 2*self.border
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[1] = FrameContainer:new{
padding = 0,
color = self.is_future and Blitbuffer.COLOR_GRAY or Blitbuffer.COLOR_BLACK,
bordersize = self.border,
width = self.width,
height = self.height,
OverlapGroup:new{
dimen = { w = inner_w },
self.daynum_w,
self.nb_not_shown_w,
self.histo_w, -- nil if not show_histo
}
}
end
function CalendarDay:updateNbNotShown(nb)
self.nb_not_shown_w:setText(string.format("+ %d ", nb))
end
function CalendarDay:onTap()
if self.callback then
self.callback()
end
return true
end
function CalendarDay:onHold()
return self:onTap()
end
local CalendarWeek = InputContainer:new{
width = nil,
height = nil,
day_width = 0,
day_padding = 0,
day_border = 0,
nb_book_spans = 0,
histo_shown = nil,
span_height = nil,
font_size = 0,
font_face = "xx_smallinfofont",
}
function CalendarWeek:init()
self.calday_widgets = {}
self.days_books = {}
end
function CalendarWeek:addDay(calday_widget)
-- Add day widget to this week widget, and update the
-- list of books read this week for later showing book
-- spans, that may span multiple days.
table.insert(self.calday_widgets, calday_widget)
local prev_day_num = #self.days_books
local prev_day_books = prev_day_num > 0 and self.days_books[#self.days_books]
local this_day_num = prev_day_num + 1
local this_day_books = {}
table.insert(self.days_books, this_day_books)
if not calday_widget.read_books then
calday_widget.read_books = {}
end
local nb_books_read = #calday_widget.read_books
if nb_books_read > self.nb_book_spans then
calday_widget:updateNbNotShown(nb_books_read - self.nb_book_spans)
end
for i=1, self.nb_book_spans do
if calday_widget.read_books[i] then
this_day_books[i] = calday_widget.read_books[i] -- brings id & title keys
this_day_books[i].span_days = 1
this_day_books[i].start_day = this_day_num
this_day_books[i].fixed = false
else
this_day_books[i] = false
end
end
if prev_day_books then
-- See if continuation from previous day, and re-order them if needed
for pn=1, #prev_day_books do
local prev_book = prev_day_books[pn]
if prev_book then
for tn=1, #this_day_books do
local this_book = this_day_books[tn]
if this_book and this_book.id == prev_book.id then
this_book.start_day = prev_book.start_day
this_book.fixed = true
this_book.span_days = prev_book.span_days + 1
-- Update span_days in all previous books
for bk = 1, prev_book.span_days do
self.days_books[this_day_num-bk][pn].span_days = this_book.span_days
end
if tn ~= pn then -- swap it with the one at previous day position
this_day_books[tn], this_day_books[pn] = this_day_books[pn], this_day_books[tn]
end
break
end
end
end
end
end
end
-- Set of { Font color, background color }
local SPAN_COLORS = {
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_WHITE },
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_GRAY_E },
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_LIGHT_GRAY },
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_GRAY },
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_WEB_GRAY },
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_DARK_GRAY },
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_DIM_GRAY },
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_BLACK },
}
function CalendarWeek:update()
self.dimen = Geom:new{w = self.width, h = self.height}
self.day_container = HorizontalGroup:new{
dimen = self.dimen:copy(),
}
for num, calday in ipairs(self.calday_widgets) do
table.insert(self.day_container, calday)
if num < #self.calday_widgets then
table.insert(self.day_container, HorizontalSpan:new{ width = self.day_padding, })
end
end
local overlaps = OverlapGroup:new{
self.day_container,
}
-- Create and add BookSpans
local bspan_margin_h = Size.margin.tiny + self.day_border
local bspan_margin_v = Size.margin.tiny
local bspan_padding_h = Size.padding.tiny
local bspan_border = Size.border.thin
-- 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 + 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
local span_w = FrameContainer:new{
width = width,
height = self.span_height,
margin = 0,
bordersize = 0,
padding_top = bspan_margin_v,
padding_bottom = bspan_margin_v,
padding_left = bspan_margin_h,
padding_right = bspan_margin_h,
overlap_offset = {offset_x, offset_y},
FrameContainer:new{
width = width - 2 * bspan_margin_h,
height = self.span_height - 2 * bspan_margin_v,
margin = 0,
padding = 0,
bordersize = bspan_border,
background = bgcolor,
CenterContainer:new{
dimen = Geom:new{
w = width - 2 * (bspan_margin_h + bspan_border),
h = self.span_height - 2 * (bspan_margin_v + bspan_border),
},
TextWidget:new{
text = BD.auto(book.title),
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,
}
}
}
}
table.insert(overlaps, span_w)
end
end
end
self[1] = LeftContainer:new{
dimen = self.dimen:copy(),
overlaps,
}
end
-- Fetched from db, cached as local as it might be expensive
local MIN_MONTH = nil
local CalendarView = InputContainer:new{
reader_statistics = nil,
monthTranslation = nil,
shortDayOfWeekTranslation = nil,
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 and self.longDayOfWeekTranslation)
}
function CalendarView:init()
self.dimen = Geom:new{
w = self.width or Screen:getWidth(),
h = self.height or Screen:getHeight(),
}
if self.dimen.w == Screen:getWidth() and self.dimen.h == Screen:getHeight() then
self.covers_fullscreen = true -- hint for UIManager:_repaint()
end
if Device:hasKeys() then
self.key_events = {
Close = { {"Back"}, doc = "close page" },
NextMonth = {{Input.group.PgFwd}, doc = "next page"},
PrevMonth = {{Input.group.PgBack}, doc = "prev page"},
}
end
if Device:isTouchDevice() then
self.ges_events.Swipe = {
GestureRange:new{
ges = "swipe",
range = self.dimen,
}
}
end
self.outer_padding = Size.padding.large
self.inner_padding = Size.padding.small
-- 7 days in a week
self.day_width = math.floor((self.dimen.w - 2*self.outer_padding - 6*self.inner_padding) / 7)
-- Put back the possible 7px lost in rounding into outer_padding
self.outer_padding = math.floor((self.dimen.w - 7*self.day_width - 6*self.inner_padding) / 2)
self.inner_dimen = Geom:new{
w = self.dimen.w - 2*self.outer_padding,
h = self.dimen.h - self.outer_padding, -- no bottom padding
}
self.content_width = self.inner_dimen.w
local now_ts = os.time()
if not MIN_MONTH then
local min_ts = self.reader_statistics:getFirstTimestamp()
if not min_ts then min_ts = now_ts end
MIN_MONTH = os.date("%Y-%m", min_ts)
end
self.min_month = MIN_MONTH
self.max_month = os.date("%Y-%m", now_ts)
if not self.cur_month then
self.cur_month = self.max_month
end
-- group for page info
local chevron_left = "chevron.left"
local chevron_right = "chevron.right"
local chevron_first = "chevron.first"
local chevron_last = "chevron.last"
if BD.mirroredUILayout() then
chevron_left, chevron_right = chevron_right, chevron_left
chevron_first, chevron_last = chevron_last, chevron_first
end
self.page_info_left_chev = Button:new{
icon = chevron_left,
callback = function() self:prevMonth() end,
bordersize = 0,
show_parent = self,
}
self.page_info_right_chev = Button:new{
icon = chevron_right,
callback = function() self:nextMonth() end,
bordersize = 0,
show_parent = self,
}
self.page_info_first_chev = Button:new{
icon = chevron_first,
callback = function() self:goToMonth(self.min_month) end,
bordersize = 0,
show_parent = self,
}
self.page_info_last_chev = Button:new{
icon = chevron_last,
callback = function() self:goToMonth(self.max_month) end,
bordersize = 0,
show_parent = self,
}
self.page_info_spacer = HorizontalSpan:new{
width = Screen:scaleBySize(32),
}
self.page_info_text = Button:new{
text = "",
hold_input = {
title = _("Enter month"),
input_func = function() return self.cur_month end,
callback = function(input)
local year, month = input:match("^(%d%d%d%d)-(%d%d)$")
if year and month then
if tonumber(month) >= 1 and tonumber(month) <= 12 and tonumber(year) >= 1000 then
-- Allow seeing arbitrary year-month in the past or future by
-- not constraining to self.min_month/max_month.
-- (year >= 1000 to ensure %Y keeps returning 4 digits)
self:goToMonth(input)
return
end
end
local InfoMessage = require("ui/widget/infomessage")
UIManager:show(InfoMessage:new{
text = _("Invalid year-month string (YYYY-MM)"),
})
end,
},
call_hold_input_on_tap = true,
bordersize = 0,
text_font_face = "pgfont",
text_font_bold = false,
}
self.page_info = HorizontalGroup:new{
self.page_info_first_chev,
self.page_info_spacer,
self.page_info_left_chev,
self.page_info_spacer,
self.page_info_text,
self.page_info_spacer,
self.page_info_right_chev,
self.page_info_spacer,
self.page_info_last_chev,
}
local footer = BottomContainer:new{
dimen = Geom:new{
w = self.inner_dimen.w,
h = self.inner_dimen.h,
},
self.page_info,
}
self.title_bar = CalendarTitle:new{
title = self.title,
width = self.content_width,
height = Size.item.height_default,
calendar_view = self,
}
-- week days names header
self.day_names = HorizontalGroup:new{}
for i = 0, 6 do
local dayname = TextWidget:new{
text = self.shortDayOfWeekTranslation[self.weekdays[(self.start_day_of_week-1+i)%7 + 1]],
face = Font:getFace("xx_smallinfofont"),
bold = true,
}
table.insert(self.day_names, FrameContainer:new{
padding = 0,
bordersize = 0,
CenterContainer:new{
dimen = Geom:new{ w = self.day_width, h = dayname:getSize().h },
dayname,
}
})
if i < 6 then
table.insert(self.day_names, HorizontalSpan:new{ width = self.inner_padding, })
end
end
-- At most 6 weeks in a month
local available_height = self.inner_dimen.h - self.title_bar:getSize().h
- self.page_info:getSize().h - self.day_names:getSize().h
self.week_height = math.floor((available_height - 7*self.inner_padding) / 6)
self.day_border = Size.border.default
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()
local content = OverlapGroup:new{
dimen = Geom:new{
w = self.inner_dimen.w,
h = self.inner_dimen.h,
},
allow_mirroring = false,
VerticalGroup:new{
align = "left",
self.title_bar,
self.day_names,
self.main_content,
},
footer,
}
-- assemble page
self[1] = FrameContainer:new{
width = self.dimen.w,
height = self.dimen.h,
padding = self.outer_padding,
padding_bottom = 0,
margin = 0,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
content
}
end
function CalendarView:_populateItems()
self.page_info:resetLayout()
self.main_content:clear()
-- See https://www.lua.org/pil/22.1.html for info about os.time() and os.date()
local month_start_ts = os.time({
year = self.cur_month:sub(1,4),
month = self.cur_month:sub(6),
day = 1,
-- When hour is unspecified, Lua defaults to noon 12h00
})
-- Update title
local month_text = self.monthTranslation[os.date("%B", month_start_ts)] .. os.date(" %Y", month_start_ts)
self.title_bar:setTitle(month_text)
-- 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 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 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)
table.insert(self.main_content, VerticalSpan:new{ width = self.inner_padding })
self.weeks = {}
local today_s = os.date("%Y-%m-%d", os.time())
local cur_ts = month_start_ts
local cur_date = os.date("*t", cur_ts)
local this_month = cur_date.month
local cur_week
while true do
cur_date = os.date("*t", cur_ts)
if cur_date.month ~= this_month then
break
end
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
cur_week = CalendarWeek:new{
height = self.week_height,
width = self.content_width,
day_width = self.day_width,
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.start_day_of_week then
-- Add fake days to fill week
local day = self.start_day_of_week
while day ~= cur_date.wday do
cur_week:addDay(CalendarDay:new{
filler = true,
height = self.week_height,
width = self.day_width,
border = self.day_border,
show_parent = self,
})
day = day + 1
if day == 8 then
day = 1
end
end
end
end
local day_s = os.date("%Y-%m-%d", cur_ts)
local day_text = string.format("%s (%s)", day_s,
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 = 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 = not is_future and function()
-- Just as ReaderStatistics:callbackDaily(), but without any window stacking
UIManager:show(KeyValuePage:new{
title = day_text,
value_align = "right",
kv_pairs = self.reader_statistics:getBooksFromPeriod(day_ts, day_ts + 86400),
callback_return = function() end -- to just have that return button shown
})
end
})
cur_ts = cur_ts + 86400 -- add one day
end
for _, week in ipairs(self.weeks) do
week:update()
end
UIManager:setDirty(self, function()
return "ui", self.dimen
end)
end
function CalendarView:nextMonth()
local t = os.time({
year = self.cur_month:sub(1,4),
month = self.cur_month:sub(6),
day = 15,
})
t = t + 86400 * 30 -- 30 days later
local next_month = os.date("%Y-%m", t)
if self.browse_future_months or next_month <= self.max_month then
self.cur_month = next_month
self:_populateItems()
end
end
function CalendarView:prevMonth()
local t = os.time({
year = self.cur_month:sub(1,4),
month = self.cur_month:sub(6),
day = 15,
})
t = t - 86400 * 30 -- 30 days before
local prev_month = os.date("%Y-%m", t)
if prev_month >= self.min_month then
self.cur_month = prev_month
self:_populateItems()
end
end
function CalendarView:goToMonth(month)
self.cur_month = month
self:_populateItems()
end
function CalendarView:onNextMonth()
self:nextMonth()
return true
end
function CalendarView:onPrevMonth()
self:prevMonth()
return true
end
function CalendarView:onSwipe(arg, ges_ev)
local direction = BD.flipDirectionIfMirroredUILayout(ges_ev.direction)
if direction == "west" then
self:nextMonth()
return true
elseif direction == "east" then
self:prevMonth()
return true
elseif direction == "south" then
-- Allow easier closing with swipe down
self:onClose()
elseif direction == "north" then
-- no use for now
do end -- luacheck: ignore 541
else -- diagonal swipe
-- trigger full refresh
UIManager:setDirty(nil, "full")
-- a long diagonal swipe may also be used for taking a screenshot,
-- so let it propagate
return false
end
end
function CalendarView:onClose()
UIManager:close(self)
return true
end
return CalendarView