2020-02-12 22:05:18 +00:00
|
|
|
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")
|
2022-11-22 19:55:27 +00:00
|
|
|
local CheckMark = require("ui/widget/checkmark")
|
2020-02-12 22:05:18 +00:00
|
|
|
local Device = require("device")
|
2022-03-04 20:20:00 +00:00
|
|
|
local FocusManager = require("ui/widget/focusmanager")
|
2020-02-12 22:05:18 +00:00
|
|
|
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 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")
|
2022-01-08 15:58:34 +00:00
|
|
|
local TitleBar = require("ui/widget/titlebar")
|
2020-02-12 22:05:18 +00:00
|
|
|
local UIManager = require("ui/uimanager")
|
|
|
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
|
|
|
local VerticalSpan = require("ui/widget/verticalspan")
|
|
|
|
local Widget = require("ui/widget/widget")
|
2022-12-11 09:16:43 +00:00
|
|
|
local datetime = require("datetime")
|
2020-02-12 22:05:18 +00:00
|
|
|
local Input = Device.input
|
|
|
|
local Screen = Device.screen
|
|
|
|
local _ = require("gettext")
|
2022-11-22 19:55:27 +00:00
|
|
|
local T = require("ffi/util").template
|
2020-02-12 22:05:18 +00:00
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local HistogramWidget = Widget:extend{
|
2020-02-12 22:05:18 +00:00
|
|
|
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)
|
2020-10-21 16:49:08 +00:00
|
|
|
if i_h == 0 and ratio > 0 then -- show at least 1px
|
|
|
|
i_h = 1
|
|
|
|
end
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local CalendarDay = InputContainer:extend{
|
2020-02-12 22:05:18 +00:00
|
|
|
daynum = nil,
|
|
|
|
ratio_per_hour = nil,
|
|
|
|
filler = false,
|
|
|
|
width = nil,
|
|
|
|
height = nil,
|
|
|
|
border = 0,
|
|
|
|
is_future = false,
|
|
|
|
font_face = "xx_smallinfofont",
|
|
|
|
font_size = nil,
|
2020-02-16 00:03:12 +00:00
|
|
|
show_histo = true,
|
2020-02-12 22:05:18 +00:00
|
|
|
histo_height = nil,
|
|
|
|
}
|
|
|
|
|
|
|
|
function CalendarDay:init()
|
|
|
|
self.dimen = Geom:new{w = self.width, h = self.height}
|
|
|
|
if self.filler then
|
|
|
|
return
|
|
|
|
end
|
2022-03-04 20:20:00 +00:00
|
|
|
self.ges_events.Tap = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "tap",
|
|
|
|
range = self.dimen,
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
2022-03-04 20:20:00 +00:00
|
|
|
}
|
|
|
|
self.ges_events.Hold = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold",
|
|
|
|
range = self.dimen,
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
2022-03-04 20:20:00 +00:00
|
|
|
}
|
2020-02-12 22:05:18 +00:00
|
|
|
|
|
|
|
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
|
2020-02-16 00:03:12 +00:00
|
|
|
if self.show_histo then
|
|
|
|
if not self.histo_height then
|
2022-10-10 20:21:27 +00:00
|
|
|
self.histo_height = inner_h * (1/3)
|
2020-02-16 00:03:12 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 22:05:18 +00:00
|
|
|
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,
|
2022-03-04 20:20:00 +00:00
|
|
|
focusable = true,
|
|
|
|
focus_border_color = Blitbuffer.COLOR_GRAY,
|
2020-02-12 22:05:18 +00:00
|
|
|
OverlapGroup:new{
|
2020-02-16 00:03:12 +00:00
|
|
|
dimen = { w = inner_w },
|
2020-02-12 22:05:18 +00:00
|
|
|
self.daynum_w,
|
|
|
|
self.nb_not_shown_w,
|
2020-02-16 00:03:12 +00:00
|
|
|
self.histo_w, -- nil if not show_histo
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local CalendarWeek = InputContainer:extend{
|
2020-02-12 22:05:18 +00:00
|
|
|
width = nil,
|
|
|
|
height = nil,
|
|
|
|
day_width = 0,
|
|
|
|
day_padding = 0,
|
|
|
|
day_border = 0,
|
|
|
|
nb_book_spans = 0,
|
2020-02-16 00:03:12 +00:00
|
|
|
histo_shown = nil,
|
2020-02-12 22:05:18 +00:00
|
|
|
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 },
|
2022-11-07 17:38:09 +00:00
|
|
|
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_GRAY_D },
|
|
|
|
{ Blitbuffer.COLOR_BLACK, Blitbuffer.COLOR_GRAY_B },
|
2022-10-30 21:34:48 +00:00
|
|
|
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_GRAY_9 },
|
2022-11-07 17:38:09 +00:00
|
|
|
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_GRAY_7 },
|
2022-10-30 21:34:48 +00:00
|
|
|
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_GRAY_5 },
|
2022-11-07 17:38:09 +00:00
|
|
|
{ Blitbuffer.COLOR_WHITE, Blitbuffer.COLOR_GRAY_3 },
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-02-16 00:03:12 +00:00
|
|
|
local bspan_padding_h = Size.padding.tiny
|
2020-02-12 22:05:18 +00:00
|
|
|
local bspan_border = Size.border.thin
|
2020-02-16 00:03:12 +00:00
|
|
|
|
|
|
|
-- 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
|
|
|
|
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
2020-02-16 00:03:12 +00:00
|
|
|
offset_y = offset_y + offset_y_fixup
|
2020-02-12 22:05:18 +00:00
|
|
|
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),
|
2020-02-16 00:03:12 +00:00
|
|
|
max_width = width - 2 * (bspan_margin_h + bspan_border + bspan_padding_h),
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
|
|
|
|
2022-11-22 19:55:27 +00:00
|
|
|
local BookDailyItem = InputContainer:extend{
|
|
|
|
item = nil,
|
|
|
|
face = Font:getFace("smallinfofont", 20),
|
|
|
|
value_width = nil,
|
|
|
|
width = nil,
|
|
|
|
height = nil,
|
|
|
|
padding = Size.padding.default,
|
|
|
|
}
|
|
|
|
|
|
|
|
function BookDailyItem:init()
|
|
|
|
self.dimen = Geom:new{x = 0, y = 0, w = self.width, h = self.height}
|
|
|
|
self.ges_events.Tap = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "tap",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.ges_events.Hold = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.checkmark_widget = CheckMark:new{
|
|
|
|
checked = self.item.checked,
|
|
|
|
}
|
|
|
|
local checked_widget = CheckMark:new{
|
|
|
|
checked = true
|
|
|
|
}
|
|
|
|
|
|
|
|
local title_max_width = self.dimen.w - 2 * Size.padding.default - checked_widget:getSize().w - self.value_width
|
|
|
|
local fgcolor, bgcolor = unpack(SPAN_COLORS[(self.item.book_id % #SPAN_COLORS)+1])
|
|
|
|
self.check_container = CenterContainer:new{
|
|
|
|
dimen = Geom:new{ w = checked_widget:getSize().w },
|
|
|
|
self.checkmark_widget,
|
|
|
|
}
|
|
|
|
self[1] = FrameContainer:new{
|
|
|
|
padding = 0,
|
|
|
|
bordersize = 0,
|
|
|
|
focusable = true,
|
|
|
|
focus_border_size = Size.border.thin,
|
|
|
|
LeftContainer:new{
|
|
|
|
dimen = Geom:new{
|
|
|
|
w = self.width,
|
|
|
|
h = self.height,
|
|
|
|
},
|
|
|
|
HorizontalGroup:new{
|
|
|
|
align = "center",
|
|
|
|
self.check_container,
|
|
|
|
CenterContainer:new{
|
|
|
|
dimen = Geom:new{ w = Size.padding.default, h = self.height },
|
|
|
|
HorizontalSpan:new{ w = Size.padding.default },
|
|
|
|
},
|
|
|
|
OverlapGroup:new{
|
|
|
|
dimen = Geom:new{ w = title_max_width, h = self.height},
|
|
|
|
allow_mirroring = false,
|
|
|
|
FrameContainer:new{
|
|
|
|
width = title_max_width,
|
|
|
|
height = self.height - 2 * Size.padding.small,
|
|
|
|
padding = 0,
|
|
|
|
padding_left = self.padding,
|
|
|
|
padding_right = self.padding,
|
|
|
|
background = bgcolor,
|
|
|
|
bordersize = Size.border.thin,
|
|
|
|
overlap_offset = { 0, Size.padding.small },
|
|
|
|
LeftContainer:new{
|
|
|
|
dimen = Geom:new{
|
|
|
|
w = title_max_width,
|
|
|
|
h = self.height - 2 * Size.padding.small,
|
|
|
|
},
|
|
|
|
TextWidget:new{
|
|
|
|
text = self.item[1],
|
|
|
|
max_width = title_max_width - 2 * self.padding,
|
|
|
|
face = self.face,
|
|
|
|
bgcolor = bgcolor,
|
|
|
|
fgcolor = fgcolor,
|
|
|
|
padding = 0,
|
|
|
|
bordersize = Size.border.thin,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
FrameContainer:new{
|
|
|
|
width = self.value_width,
|
|
|
|
padding = 0,
|
|
|
|
padding_left = Size.padding.default,
|
|
|
|
bordersize = 0,
|
|
|
|
LeftContainer:new{
|
|
|
|
dimen = Geom:new{ w = self.value_width, h = self.height},
|
|
|
|
padding = 0,
|
|
|
|
TextWidget:new{
|
|
|
|
text = self.item[2],
|
|
|
|
max_width = self.value_width,
|
|
|
|
face = self.face
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
checked_widget:free()
|
|
|
|
self[1].invert = self.invert
|
|
|
|
end
|
|
|
|
|
|
|
|
function BookDailyItem:onTap(_, ges)
|
|
|
|
local x_intersect = function()
|
|
|
|
local dimen = self.checkmark_widget.dimen
|
|
|
|
return ges.pos.x >= dimen.x - dimen.w and ges.pos.x <= dimen.x + 2 * dimen.w
|
|
|
|
end
|
|
|
|
if self.item.check_cb and x_intersect() then
|
|
|
|
self.item:check_cb()
|
|
|
|
self.checkmark_widget = CheckMark:new{
|
|
|
|
checked = self.item.checked,
|
|
|
|
}
|
|
|
|
self.check_container[1] = self.checkmark_widget
|
|
|
|
UIManager:setDirty(self, function()
|
|
|
|
return "ui", self.check_container.dimen
|
|
|
|
end)
|
|
|
|
elseif self.item.callback then
|
|
|
|
self.item:callback()
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function BookDailyItem:onHold()
|
|
|
|
if self.item.hold_callback then
|
|
|
|
self.item.hold_callback(self.show_parent, self.item)
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
local CalendarDayView = FocusManager:extend{
|
|
|
|
day_ts = nil,
|
|
|
|
show_page = 1,
|
|
|
|
kv_pairs = {},
|
2022-11-26 15:56:06 +00:00
|
|
|
NB_VERTICAL_SEPARATORS_PER_HOUR = 6 -- one vertical line every 10 minutes
|
2022-11-22 19:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function CalendarDayView:init()
|
|
|
|
self.dimen = Geom:new{
|
|
|
|
x = 0,
|
|
|
|
y = 0,
|
|
|
|
w = Screen:getWidth(),
|
|
|
|
h = Screen:getHeight(),
|
|
|
|
}
|
|
|
|
if Device:hasKeys() then
|
|
|
|
self.key_events.Close = { { Device.input.group.Back } }
|
|
|
|
self.key_events.NextPage = { { Device.input.group.PgFwd } }
|
|
|
|
self.key_events.PrevPage = { { Device.input.group.PgBack } }
|
|
|
|
end
|
|
|
|
if Device:isTouchDevice() then
|
|
|
|
self.ges_events.Swipe = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "swipe",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
self.ges_events.MultiSwipe = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "multiswipe",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.outer_padding = Size.padding.large
|
|
|
|
self.inner_padding = Size.padding.small
|
|
|
|
local min_month = self.min_month or os.date("%Y-%m", self.reader_statistics:getFirstTimestamp() or os.time())
|
|
|
|
self.min_ts = os.time({
|
|
|
|
year = min_month:sub(1, 4),
|
|
|
|
month = min_month:sub(6),
|
|
|
|
day = 0
|
|
|
|
})
|
|
|
|
|
|
|
|
self.title_bar = TitleBar:new{
|
|
|
|
fullscreen = true,
|
|
|
|
width = self.dimen.w,
|
|
|
|
align = "left",
|
|
|
|
title = self.title or "Title",
|
|
|
|
title_face = Font:getFace("smalltfont", 22),
|
|
|
|
title_h_padding = self.outer_padding,
|
|
|
|
close_callback = function() self:onClose() end,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
|
|
|
|
self.titlebar_height = self.title_bar:getHeight()
|
|
|
|
|
|
|
|
local padding = Size.padding.large
|
|
|
|
local footer_width = self.dimen.w - 2 * padding
|
|
|
|
self.footer_center_width = math.floor(footer_width * 0.32)
|
|
|
|
self.footer_button_width = math.floor(footer_width * 0.10)
|
|
|
|
|
|
|
|
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.footer_left = Button:new{
|
|
|
|
icon = chevron_left,
|
|
|
|
width = self.footer_button_width,
|
|
|
|
callback = function() self:prevPage() end,
|
|
|
|
bordersize = 0,
|
|
|
|
radius = 0,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
self.footer_right = Button:new{
|
|
|
|
icon = chevron_right,
|
|
|
|
width = self.footer_button_width,
|
|
|
|
callback = function() self:nextPage() end,
|
|
|
|
bordersize = 0,
|
|
|
|
radius = 0,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
self.footer_first_up = Button:new{
|
|
|
|
icon = chevron_first,
|
|
|
|
width = self.footer_button_width,
|
|
|
|
callback = function()
|
|
|
|
self:goToPage(1)
|
|
|
|
end,
|
|
|
|
bordersize = 0,
|
|
|
|
radius = 0,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
self.footer_last_down = Button:new{
|
|
|
|
icon = chevron_last,
|
|
|
|
width = self.footer_button_width,
|
|
|
|
callback = function()
|
|
|
|
self:goToPage(self.pages)
|
|
|
|
end,
|
|
|
|
bordersize = 0,
|
|
|
|
radius = 0,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
self.footer_page = Button:new{
|
|
|
|
text = "",
|
|
|
|
hold_input = {
|
|
|
|
title = _("Enter page number"),
|
2024-06-15 06:54:17 +00:00
|
|
|
input_type = "number",
|
2022-11-22 19:55:27 +00:00
|
|
|
hint_func = function()
|
2024-06-15 06:54:17 +00:00
|
|
|
return string.format("(1 - %s)", self.pages)
|
2022-11-22 19:55:27 +00:00
|
|
|
end,
|
|
|
|
callback = function(input)
|
|
|
|
local page = tonumber(input)
|
|
|
|
if page and page >= 1 and page <= self.pages then
|
|
|
|
self:goToPage(page)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
ok_text = _("Go to page"),
|
|
|
|
},
|
|
|
|
call_hold_input_on_tap = true,
|
|
|
|
bordersize = 0,
|
|
|
|
margin = 0,
|
|
|
|
text_font_face = "pgfont",
|
|
|
|
text_font_bold = false,
|
|
|
|
width = self.footer_center_width,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
self.page_info = HorizontalGroup:new{
|
|
|
|
self.footer_first_up,
|
|
|
|
self.footer_left,
|
|
|
|
self.footer_page,
|
|
|
|
self.footer_right,
|
|
|
|
self.footer_last_down,
|
|
|
|
}
|
|
|
|
self.footer_height = self.page_info:getSize().h
|
|
|
|
|
|
|
|
self.items_per_page = 5
|
|
|
|
|
|
|
|
local temp_text = TextWidget:new{
|
|
|
|
text = " ",
|
|
|
|
face = BookDailyItem.face
|
|
|
|
}
|
|
|
|
self.book_item_height = temp_text:getSize().h + 2 * Size.padding.small
|
|
|
|
temp_text:free()
|
|
|
|
|
|
|
|
self.book_items = VerticalGroup:new{}
|
|
|
|
self.timeline = OverlapGroup:new{
|
|
|
|
dimen = self.dimen:copy(),
|
|
|
|
}
|
|
|
|
self.footer_container = BottomContainer:new{
|
|
|
|
dimen = self.dimen:copy()
|
|
|
|
}
|
|
|
|
self:setupView()
|
|
|
|
|
|
|
|
self[1] = FrameContainer:new{
|
|
|
|
height = self.dimen.h,
|
|
|
|
padding = 0,
|
|
|
|
bordersize = 0,
|
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
|
|
OverlapGroup:new{
|
|
|
|
dimen = self.dimen:copy(),
|
|
|
|
FrameContainer:new{
|
|
|
|
height = self.dimen.h,
|
|
|
|
padding = 0,
|
|
|
|
bordersize = 0,
|
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
|
|
VerticalGroup:new{
|
|
|
|
self.title_bar,
|
|
|
|
self.book_items
|
|
|
|
}
|
|
|
|
},
|
|
|
|
self.timeline,
|
|
|
|
self.footer_container,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:setupView()
|
2022-11-26 15:56:06 +00:00
|
|
|
local now = os.time()
|
|
|
|
self.is_current_day = now >= self.day_ts and now < self.day_ts + 86400
|
|
|
|
if self.is_current_day then
|
|
|
|
local date = os.date("*t", now)
|
2023-04-01 17:15:36 +00:00
|
|
|
self.current_day_hour = date.hour - (self.reader_statistics.settings.calendar_day_start_hour or 0)
|
|
|
|
self.current_hour_second = date.min * 60 + date.sec - (self.reader_statistics.settings.calendar_day_start_minute or 0) * 60
|
|
|
|
if self.current_hour_second < 0 then
|
|
|
|
self.current_day_hour = self.current_day_hour - 1
|
|
|
|
self.current_hour_second = 3600 + self.current_hour_second
|
|
|
|
end
|
2023-04-07 07:02:23 +00:00
|
|
|
if self.current_day_hour < 0 then
|
|
|
|
-- showing previous day
|
|
|
|
self.current_day_hour = self.current_day_hour + 24
|
|
|
|
end
|
2022-11-26 15:56:06 +00:00
|
|
|
end
|
|
|
|
|
2022-11-22 19:55:27 +00:00
|
|
|
self.kv_pairs = self.reader_statistics:getBooksFromPeriod(self.day_ts, self.day_ts + 86400)
|
|
|
|
local seconds_books = self.reader_statistics:getReadingDurationBySecond(self.day_ts)
|
|
|
|
for _, kv in ipairs(self.kv_pairs) do
|
|
|
|
if seconds_books[kv.book_id] then
|
|
|
|
kv.periods = seconds_books[kv.book_id].periods
|
|
|
|
end
|
|
|
|
kv.checked = true
|
|
|
|
end
|
2023-04-01 17:15:36 +00:00
|
|
|
table.sort(self.kv_pairs, function(a,b) return a.duration > b.duration end) --sort by value
|
2023-04-07 07:02:23 +00:00
|
|
|
self.title = self:getTitle()
|
2022-11-22 19:55:27 +00:00
|
|
|
|
|
|
|
self.show_page = 1
|
|
|
|
self.title_bar:setTitle(self.title)
|
|
|
|
|
|
|
|
for _, kv in ipairs(self.kv_pairs) do
|
|
|
|
kv.check_cb = function(this)
|
|
|
|
this.checked = not this.checked
|
|
|
|
self:refreshTimeline()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local temp_check = CheckMark:new{ checked = true }
|
|
|
|
self.time_text_width = temp_check:getSize().w + self.outer_padding + Size.padding.default
|
|
|
|
temp_check:free()
|
|
|
|
|
|
|
|
local font_size = TextWidget:getFontSizeToFitHeight("cfont", self.time_text_width, Size.padding.small)
|
|
|
|
self.time_text_face = Font:getFace("cfont", font_size)
|
|
|
|
local temp_text = TextWidget:new{
|
|
|
|
text = "00:00",
|
|
|
|
face = self.time_text_face
|
|
|
|
}
|
|
|
|
local time_text_width = temp_text:getSize().w
|
|
|
|
while time_text_width > self.time_text_width * 0.8 do
|
|
|
|
font_size = font_size * 0.8
|
|
|
|
self.time_text_face = Font:getFace("cfont", font_size)
|
2022-11-26 15:56:06 +00:00
|
|
|
temp_text:free()
|
2022-11-22 19:55:27 +00:00
|
|
|
temp_text = TextWidget:new{
|
|
|
|
text = "00:00",
|
|
|
|
face = self.time_text_face
|
|
|
|
}
|
|
|
|
time_text_width = temp_text:getWidth()
|
|
|
|
end
|
|
|
|
temp_text:free()
|
|
|
|
|
|
|
|
self.pages = #self.kv_pairs <= self.items_per_page+1 and 1 or math.ceil(#self.kv_pairs / self.items_per_page)
|
|
|
|
self.footer_container[1] = self.pages > 1 and self.page_info or VerticalSpan:new{ w = 0 }
|
|
|
|
|
|
|
|
self:_populateBooks()
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:nextPage()
|
|
|
|
local new_page = math.min(self.show_page+1, self.pages)
|
|
|
|
if new_page > self.show_page then
|
|
|
|
self.show_page = new_page
|
|
|
|
self:_populateBooks()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:prevPage()
|
|
|
|
local new_page = math.max(self.show_page-1, 1)
|
|
|
|
if new_page < self.show_page then
|
|
|
|
self.show_page = new_page
|
|
|
|
self:_populateBooks()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:goToPage(page)
|
|
|
|
self.show_page = page
|
|
|
|
self:_populateBooks()
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:onNextPage()
|
2023-04-01 17:15:36 +00:00
|
|
|
if not self:nextPage() and self.day_ts + 82800 < os.time() then
|
|
|
|
local current_day_ts = self.day_ts - (self.reader_statistics.settings.calendar_day_start_hour or 0) * 3600
|
|
|
|
- (self.reader_statistics.settings.calendar_day_start_minute or 0) * 60
|
|
|
|
local next_day_ts = current_day_ts + 86400 + 10800 -- make sure it's the next day
|
|
|
|
local next_day_date = os.date("*t", next_day_ts)
|
|
|
|
next_day_ts = os.time({
|
|
|
|
year = next_day_date.year,
|
|
|
|
month = next_day_date.month,
|
|
|
|
day = next_day_date.day,
|
|
|
|
hour = 0,
|
|
|
|
min = 0,
|
|
|
|
})
|
|
|
|
local current_day_length = next_day_ts - current_day_ts
|
|
|
|
if self.day_ts + current_day_length < os.time() then
|
|
|
|
-- go to next day
|
|
|
|
self.day_ts = self.day_ts + current_day_length
|
|
|
|
self:setupView()
|
|
|
|
end
|
2022-11-22 19:55:27 +00:00
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:onPrevPage()
|
2023-04-01 17:15:36 +00:00
|
|
|
if not self:prevPage() and self.day_ts - 82800 >= self.min_ts then
|
|
|
|
local current_day_ts = self.day_ts - (self.reader_statistics.settings.calendar_day_start_hour or 0) * 3600
|
|
|
|
- (self.reader_statistics.settings.calendar_day_start_minute or 0) * 60
|
|
|
|
local previous_day_ts = current_day_ts - 86400 + 10800 -- make sure it's the previous day
|
|
|
|
local previous_day_date = os.date("*t", previous_day_ts)
|
|
|
|
previous_day_ts = os.time({
|
|
|
|
year = previous_day_date.year,
|
|
|
|
month = previous_day_date.month,
|
|
|
|
day = previous_day_date.day,
|
|
|
|
hour = 0,
|
|
|
|
min = 0,
|
|
|
|
})
|
|
|
|
local previous_day_length = current_day_ts - previous_day_ts
|
|
|
|
if self.day_ts - previous_day_length >= self.min_ts then
|
|
|
|
-- go to previous day
|
|
|
|
self.day_ts = self.day_ts - previous_day_length
|
|
|
|
self:setupView()
|
|
|
|
end
|
2022-11-22 19:55:27 +00:00
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:_populateBooks()
|
|
|
|
self.book_items:clear()
|
|
|
|
self.layout = {}
|
|
|
|
local idx_offset = (self.show_page - 1) * self.items_per_page
|
|
|
|
local page_last = #self.kv_pairs
|
|
|
|
if self.pages > 1 and idx_offset + self.items_per_page < #self.kv_pairs then
|
|
|
|
page_last = idx_offset + self.items_per_page
|
|
|
|
end
|
|
|
|
|
|
|
|
local value_width = 0
|
|
|
|
local value_text = TextWidget:new{
|
|
|
|
text = "",
|
|
|
|
face = BookDailyItem.face
|
|
|
|
}
|
|
|
|
for idx = idx_offset+1, page_last do
|
|
|
|
value_text:setText( self.kv_pairs[idx][2] )
|
|
|
|
value_width = math.max(value_width, value_text:getSize().w)
|
|
|
|
end
|
|
|
|
value_text:free()
|
|
|
|
|
|
|
|
for idx = idx_offset+1, page_last do
|
|
|
|
local item = BookDailyItem:new{
|
|
|
|
item = self.kv_pairs[idx],
|
|
|
|
width = self.dimen.w - 2 * self.outer_padding,
|
|
|
|
value_width = value_width,
|
|
|
|
height = self.book_item_height,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
|
|
|
table.insert(self.layout, { item })
|
|
|
|
table.insert(self.book_items, item)
|
|
|
|
end
|
|
|
|
self.timeline_offset = self.titlebar_height + #self.book_items * self.book_item_height + Size.padding.default
|
|
|
|
self.timeline_height = self.dimen.h - self.timeline_offset
|
|
|
|
if self.pages > 1 then
|
|
|
|
self.footer_page:setText(T(_("Page %1 of %2"), self.show_page, self.pages), self.footer_center_width)
|
|
|
|
self.footer_page:enable()
|
|
|
|
|
|
|
|
self.footer_left:enableDisable(self.show_page > 1)
|
|
|
|
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)
|
|
|
|
|
|
|
|
self.timeline_height = self.timeline_height - self.footer_height
|
|
|
|
else
|
|
|
|
self.timeline_height = self.timeline_height - Size.padding.default
|
|
|
|
end
|
2022-11-26 15:56:06 +00:00
|
|
|
self.hour_height = math.floor(self.timeline_height / 24)
|
2022-11-22 19:55:27 +00:00
|
|
|
self.timeline_width = self.dimen.w - self.outer_padding - self.time_text_width
|
|
|
|
|
|
|
|
if #self.kv_pairs == 0 then
|
|
|
|
-- Needed when the first opened day has no data, then move to another day with data
|
|
|
|
table.insert(self.book_items, CenterContainer:new{
|
|
|
|
dimen = Geom:new { w = self.dimen.w - 2 * self.outer_padding, h = 0},
|
|
|
|
VerticalSpan:new{ w = 0 }
|
|
|
|
})
|
|
|
|
end
|
|
|
|
self:refreshTimeline()
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:refreshTimeline()
|
|
|
|
self.timeline:clear()
|
|
|
|
|
2022-11-26 15:56:06 +00:00
|
|
|
-- Draw decorations first, so read spans can be drawn over them
|
|
|
|
-- Vertical lines (first, so horizontal lines can override them if we use another color)
|
|
|
|
for i=0, self.NB_VERTICAL_SEPARATORS_PER_HOUR do
|
|
|
|
local offset_x = self.time_text_width + self.timeline_width * i / self.NB_VERTICAL_SEPARATORS_PER_HOUR
|
|
|
|
table.insert(self.timeline, FrameContainer:new{
|
|
|
|
width = Size.border.thin,
|
|
|
|
height = 24 * self.hour_height, -- unscaled_size_check: ignore
|
|
|
|
background = Blitbuffer.COLOR_LIGHT_GRAY,
|
|
|
|
bordersize = 0,
|
|
|
|
padding = 0,
|
|
|
|
overlap_offset = { offset_x, self.timeline_offset },
|
|
|
|
VerticalSpan:new{ w = 0 }
|
|
|
|
})
|
|
|
|
end
|
|
|
|
-- Hour indicator
|
2022-11-22 19:55:27 +00:00
|
|
|
for i=0, 23 do
|
2022-11-26 15:56:06 +00:00
|
|
|
local offset_y = self.timeline_offset + self.hour_height * i
|
2022-11-22 19:55:27 +00:00
|
|
|
table.insert(self.timeline, FrameContainer:new{
|
|
|
|
width = self.time_text_width,
|
2022-11-26 15:56:06 +00:00
|
|
|
height = self.hour_height,
|
2022-11-22 19:55:27 +00:00
|
|
|
margin = 0,
|
|
|
|
padding = 0,
|
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
|
|
bordersize = 0,
|
|
|
|
overlap_offset = {0, offset_y},
|
|
|
|
CenterContainer:new{
|
2022-11-26 15:56:06 +00:00
|
|
|
dimen = Geom:new{ w = self.time_text_width, h = self.hour_height},
|
2022-11-22 19:55:27 +00:00
|
|
|
TextWidget:new{
|
2023-04-01 17:15:36 +00:00
|
|
|
text = string.format("%02d:%02d",
|
|
|
|
(i + (self.reader_statistics.settings.calendar_day_start_hour or 0)) % 24,
|
|
|
|
self.reader_statistics.settings.calendar_day_start_minute or 0
|
|
|
|
),
|
2022-11-22 19:55:27 +00:00
|
|
|
face = self.time_text_face,
|
|
|
|
padding = Size.padding.small
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2022-11-26 15:56:06 +00:00
|
|
|
end
|
|
|
|
-- Horizontal lines
|
2023-04-02 12:40:10 +00:00
|
|
|
local idx_00h00
|
|
|
|
if self.reader_statistics.settings.calendar_day_start_hour and self.reader_statistics.settings.calendar_day_start_hour ~= 0 then
|
|
|
|
idx_00h00 = 24 - self.reader_statistics.settings.calendar_day_start_hour
|
|
|
|
end
|
2022-11-26 15:56:06 +00:00
|
|
|
for i=0, 24 do
|
|
|
|
local offset_y = self.timeline_offset + self.hour_height * i
|
2023-04-02 12:40:10 +00:00
|
|
|
local height = Size.border.default
|
|
|
|
if idx_00h00 and i == idx_00h00 then
|
|
|
|
-- Thicker separator between 23:00 and 00:00
|
|
|
|
offset_y = offset_y - math.floor(height/2) -- shift it a bit up
|
|
|
|
height = height * 2
|
|
|
|
end
|
2022-11-26 15:56:06 +00:00
|
|
|
table.insert(self.timeline, FrameContainer:new{
|
|
|
|
width = self.timeline_width,
|
2023-04-02 12:40:10 +00:00
|
|
|
height = height,
|
2022-11-26 15:56:06 +00:00
|
|
|
background = Blitbuffer.COLOR_LIGHT_GRAY,
|
|
|
|
bordersize = 0,
|
|
|
|
padding = 0,
|
|
|
|
overlap_offset = { self.time_text_width, offset_y - Size.border.thin },
|
|
|
|
CenterContainer:new{
|
|
|
|
dimen = Geom:new{ w = self.timeline_width, h = Size.border.default },
|
|
|
|
VerticalSpan:new{ w = 0 }
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
-- Current time arrow indicator
|
|
|
|
if self.is_current_day then
|
|
|
|
-- Get the arrow glyph a bit bigger than what it is with the hour indicator font
|
|
|
|
local font_size = TextWidget:getFontSizeToFitHeight("cfont", self.hour_height*1.1, 0)
|
|
|
|
local current_time_icon = TextWidget:new{
|
|
|
|
text = "\u{25B2}", -- black up-pointing triangle
|
|
|
|
face = Font:getFace("cfont", font_size),
|
|
|
|
padding = 0,
|
|
|
|
}
|
|
|
|
local offset_x = self.time_text_width + math.floor( self.timeline_width * self.current_hour_second / 3600 - current_time_icon:getWidth()/2)
|
|
|
|
local offset_y = self.timeline_offset + self.hour_height * (self.current_day_hour + 1)
|
|
|
|
offset_y = offset_y - math.floor(self.hour_height*0.3) -- move it up so it sits over the horizontal line
|
|
|
|
current_time_icon.overlap_offset = { offset_x, offset_y }
|
|
|
|
table.insert(self.timeline, current_time_icon)
|
|
|
|
end
|
|
|
|
-- Finally, the read books spans
|
|
|
|
for _, v in ipairs(self.kv_pairs) do
|
|
|
|
if v.checked and v.periods then
|
|
|
|
local fgcolor, bgcolor = unpack(SPAN_COLORS[(v.book_id % #SPAN_COLORS)+1])
|
|
|
|
for _, period in ipairs(v.periods) do
|
|
|
|
local start_hour = math.floor(period.start / 3600)
|
|
|
|
local finish_hour = math.floor(period.finish / 3600)
|
|
|
|
for i=0, finish_hour-start_hour do
|
|
|
|
local start = i==0 and period.start or (start_hour+i) * 3600
|
|
|
|
if start >= 24 * 3600 then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
local finish = i==finish_hour-start_hour and period.finish or (start_hour+i+1) * 3600 - 1
|
|
|
|
local span = self:generateSpan(start, finish, bgcolor, fgcolor, v[1])
|
|
|
|
if span then table.insert(self.timeline, span) end
|
|
|
|
end
|
|
|
|
end
|
2022-11-22 19:55:27 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
UIManager:setDirty(self, function()
|
|
|
|
return "ui", self.dimen
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:generateSpan(start, finish, bgcolor, fgcolor, title)
|
|
|
|
local width = math.floor((finish - start)/3600*self.timeline_width)
|
|
|
|
if width <= 0 then return end
|
|
|
|
local start_hour = math.floor(start / 3600)
|
2022-11-26 15:56:06 +00:00
|
|
|
local offset_y = start_hour * self.hour_height + self.inner_padding + self.timeline_offset
|
2022-11-22 19:55:27 +00:00
|
|
|
local offset_x = self.time_text_width + math.floor((start % 3600) / 3600 * self.timeline_width)
|
|
|
|
|
2022-11-26 15:56:06 +00:00
|
|
|
local font_size = TextWidget:getFontSizeToFitHeight("cfont", self.hour_height - 2 * self.inner_padding, 0.3)
|
2022-11-22 19:55:27 +00:00
|
|
|
local min_width = TextWidget:new{
|
|
|
|
text = "…",
|
|
|
|
face = Font:getFace("cfont", font_size),
|
|
|
|
padding = 0.3
|
|
|
|
}:getWidth()
|
|
|
|
return FrameContainer:new{
|
|
|
|
width = width,
|
2022-11-26 15:56:06 +00:00
|
|
|
height = self.hour_height - 2 * self.inner_padding,
|
2022-11-22 19:55:27 +00:00
|
|
|
bordersize = Size.border.thin,
|
|
|
|
overlap_offset = {offset_x, offset_y},
|
|
|
|
background = bgcolor,
|
|
|
|
padding = 0.3,
|
|
|
|
CenterContainer:new{
|
2022-11-26 15:56:06 +00:00
|
|
|
dimen = Geom:new{ h = self.hour_height - 2 * self.inner_padding, w = width },
|
2022-11-22 19:55:27 +00:00
|
|
|
width > min_width and TextWidget:new{
|
|
|
|
text = title,
|
|
|
|
face = Font:getFace("cfont", font_size),
|
|
|
|
padding = 0,
|
|
|
|
fgcolor = fgcolor,
|
|
|
|
max_width = width
|
|
|
|
} or HorizontalSpan:new{ w = 0 },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:removeKeyValueItem(item)
|
|
|
|
for i, v in ipairs(self.kv_pairs) do
|
|
|
|
if v.book_id == item.book_id then
|
|
|
|
table.remove(self.kv_pairs, i)
|
|
|
|
self:_populateBooks()
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:onSwipe(arg, ges_ev)
|
|
|
|
local direction = BD.flipDirectionIfMirroredUILayout(ges_ev.direction)
|
|
|
|
if direction == "west" then
|
|
|
|
self:onNextPage()
|
|
|
|
elseif direction == "east" then
|
|
|
|
self:onPrevPage()
|
|
|
|
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 CalendarDayView:onMultiSwipe(arg, ges_ev)
|
|
|
|
self:onClose()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarDayView:onClose()
|
|
|
|
UIManager:close(self)
|
|
|
|
UIManager:setDirty(nil, "ui")
|
|
|
|
if self.close_callback then
|
|
|
|
self:close_callback()
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2020-02-12 22:05:18 +00:00
|
|
|
-- Fetched from db, cached as local as it might be expensive
|
|
|
|
local MIN_MONTH = nil
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local CalendarView = FocusManager:extend{
|
2020-02-12 22:05:18 +00:00
|
|
|
reader_statistics = nil,
|
2020-02-16 00:03:12 +00:00
|
|
|
start_day_of_week = 2, -- 2 = Monday, 1-7 = Sunday-Saturday
|
|
|
|
show_hourly_histogram = true,
|
|
|
|
browse_future_months = false,
|
2020-02-12 22:05:18 +00:00
|
|
|
nb_book_spans = 3,
|
2020-02-16 00:03:12 +00:00
|
|
|
font_face = "xx_smallinfofont",
|
2020-02-12 22:05:18 +00:00
|
|
|
title = "",
|
|
|
|
width = nil,
|
|
|
|
height = nil,
|
|
|
|
cur_month = nil,
|
|
|
|
weekdays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } -- in Lua wday order
|
2022-12-11 09:16:43 +00:00
|
|
|
-- (These do not need translations: they are the keys into the datetime module translations)
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
|
|
|
|
2023-04-07 07:02:23 +00:00
|
|
|
function CalendarDayView:getTitle()
|
|
|
|
local day_ts = self.day_ts - (self.reader_statistics.settings.calendar_day_start_hour or 0) * 3600
|
|
|
|
- (self.reader_statistics.settings.calendar_day_start_minute or 0) * 60
|
|
|
|
local day = os.date("%Y-%m-%d", day_ts + 10800) -- use 03:00 to determine date (summer time change)
|
|
|
|
local date = os.date("*t", day_ts + 10800)
|
|
|
|
return string.format("%s (%s)", day, datetime.shortDayOfWeekToLongTranslation[CalendarView.weekdays[date.wday]])
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
2022-10-27 00:01:51 +00:00
|
|
|
self.key_events.Close = { { Input.group.Back } }
|
|
|
|
self.key_events.NextMonth = { { Input.group.PgFwd } }
|
|
|
|
self.key_events.PrevMonth = { { Input.group.PgBack } }
|
2020-02-12 22:05:18 +00:00
|
|
|
end
|
|
|
|
if Device:isTouchDevice() then
|
|
|
|
self.ges_events.Swipe = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "swipe",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
2022-01-25 14:24:06 +00:00
|
|
|
self.ges_events.MultiSwipe = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "multiswipe",
|
|
|
|
range = self.dimen,
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 22:05:18 +00:00
|
|
|
end
|
|
|
|
|
[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 04:15:23 +00:00
|
|
|
self.outer_padding = Size.padding.large
|
2020-02-12 22:05:18 +00:00
|
|
|
self.inner_padding = Size.padding.small
|
|
|
|
|
|
|
|
-- 7 days in a week
|
2022-10-10 20:21:27 +00:00
|
|
|
self.day_width = math.floor((self.dimen.w - 2*self.outer_padding - 6*self.inner_padding) * (1/7))
|
2020-02-12 22:05:18 +00:00
|
|
|
-- Put back the possible 7px lost in rounding into outer_padding
|
2022-10-10 20:21:27 +00:00
|
|
|
self.outer_padding = math.floor((self.dimen.w - 7*self.day_width - 6*self.inner_padding) * (1/2))
|
[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 04:15:23 +00:00
|
|
|
|
2022-01-08 15:58:34 +00:00
|
|
|
self.content_width = self.dimen.w - 2*self.outer_padding
|
2020-02-12 22:05:18 +00:00
|
|
|
|
2020-10-18 18:38:17 +00:00
|
|
|
local now_ts = os.time()
|
2020-02-12 22:05:18 +00:00
|
|
|
if not MIN_MONTH then
|
|
|
|
local min_ts = self.reader_statistics:getFirstTimestamp()
|
2020-10-18 18:38:17 +00:00
|
|
|
if not min_ts then min_ts = now_ts end
|
2020-02-12 22:05:18 +00:00
|
|
|
MIN_MONTH = os.date("%Y-%m", min_ts)
|
|
|
|
end
|
|
|
|
self.min_month = MIN_MONTH
|
2020-10-18 18:38:17 +00:00
|
|
|
self.max_month = os.date("%Y-%m", now_ts)
|
2020-02-12 22:05:18 +00:00
|
|
|
if not self.cur_month then
|
|
|
|
self.cur_month = self.max_month
|
|
|
|
end
|
|
|
|
|
|
|
|
-- group for page info
|
2020-12-19 11:18:30 +00:00
|
|
|
local chevron_left = "chevron.left"
|
|
|
|
local chevron_right = "chevron.right"
|
|
|
|
local chevron_first = "chevron.first"
|
|
|
|
local chevron_last = "chevron.last"
|
2020-02-12 22:05:18 +00:00
|
|
|
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,
|
|
|
|
},
|
[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 04:15:23 +00:00
|
|
|
call_hold_input_on_tap = true,
|
2020-02-12 22:05:18 +00:00
|
|
|
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,
|
[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 04:15:23 +00:00
|
|
|
self.page_info_spacer,
|
2020-02-12 22:05:18 +00:00
|
|
|
self.page_info_text,
|
[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 04:15:23 +00:00
|
|
|
self.page_info_spacer,
|
2020-02-12 22:05:18 +00:00
|
|
|
self.page_info_right_chev,
|
|
|
|
self.page_info_spacer,
|
|
|
|
self.page_info_last_chev,
|
|
|
|
}
|
|
|
|
|
|
|
|
local footer = BottomContainer:new{
|
2022-01-08 15:58:34 +00:00
|
|
|
-- (BottomContainer does horizontal centering)
|
2020-02-12 22:05:18 +00:00
|
|
|
dimen = Geom:new{
|
2022-01-08 15:58:34 +00:00
|
|
|
w = self.dimen.w,
|
|
|
|
h = self.dimen.h,
|
2020-02-12 22:05:18 +00:00
|
|
|
},
|
|
|
|
self.page_info,
|
|
|
|
}
|
|
|
|
|
2022-01-08 15:58:34 +00:00
|
|
|
self.title_bar = TitleBar:new{
|
|
|
|
fullscreen = self.covers_fullscreen,
|
|
|
|
width = self.dimen.w,
|
|
|
|
align = "left",
|
2020-02-12 22:05:18 +00:00
|
|
|
title = self.title,
|
2022-01-08 15:58:34 +00:00
|
|
|
title_h_padding = self.outer_padding, -- have month name aligned with calendar left edge
|
|
|
|
close_callback = function() self:onClose() end,
|
|
|
|
show_parent = self,
|
2020-02-12 22:05:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-- week days names header
|
|
|
|
self.day_names = HorizontalGroup:new{}
|
2022-01-08 15:58:34 +00:00
|
|
|
table.insert(self.day_names, HorizontalSpan:new{ width = self.outer_padding })
|
2020-02-12 22:05:18 +00:00
|
|
|
for i = 0, 6 do
|
|
|
|
local dayname = TextWidget:new{
|
2022-12-11 09:16:43 +00:00
|
|
|
text = datetime.shortDayOfWeekTranslation[self.weekdays[(self.start_day_of_week-1+i)%7 + 1]],
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
2022-01-08 15:58:34 +00:00
|
|
|
local available_height = self.dimen.h - self.title_bar:getHeight()
|
2020-02-12 22:05:18 +00:00
|
|
|
- self.page_info:getSize().h - self.day_names:getSize().h
|
2022-10-10 20:21:27 +00:00
|
|
|
self.week_height = math.floor((available_height - 7*self.inner_padding) * (1/6))
|
2020-02-12 22:05:18 +00:00
|
|
|
self.day_border = Size.border.default
|
2020-02-16 00:03:12 +00:00
|
|
|
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
|
2020-02-12 22:05:18 +00:00
|
|
|
|
|
|
|
self.main_content = VerticalGroup:new{}
|
|
|
|
self:_populateItems()
|
|
|
|
|
|
|
|
local content = OverlapGroup:new{
|
|
|
|
dimen = Geom:new{
|
2022-01-08 15:58:34 +00:00
|
|
|
w = self.dimen.w,
|
|
|
|
h = self.dimen.h,
|
2020-02-12 22:05:18 +00:00
|
|
|
},
|
|
|
|
allow_mirroring = false,
|
|
|
|
VerticalGroup:new{
|
|
|
|
align = "left",
|
|
|
|
self.title_bar,
|
|
|
|
self.day_names,
|
2022-01-08 15:58:34 +00:00
|
|
|
HorizontalGroup:new{
|
|
|
|
HorizontalSpan:new{ width = self.outer_padding },
|
|
|
|
self.main_content,
|
|
|
|
},
|
2020-02-12 22:05:18 +00:00
|
|
|
},
|
|
|
|
footer,
|
|
|
|
}
|
|
|
|
-- assemble page
|
|
|
|
self[1] = FrameContainer:new{
|
|
|
|
width = self.dimen.w,
|
|
|
|
height = self.dimen.h,
|
2022-01-08 15:58:34 +00:00
|
|
|
padding = 0,
|
[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 04:15:23 +00:00
|
|
|
margin = 0,
|
2020-02-12 22:05:18 +00:00
|
|
|
bordersize = 0,
|
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
|
|
content
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function CalendarView:_populateItems()
|
2022-03-04 20:20:00 +00:00
|
|
|
self.layout = {}
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
2022-12-11 09:16:43 +00:00
|
|
|
local month_text = datetime.longMonthTranslation[os.date("%B", month_start_ts)] .. os.date(" %Y", month_start_ts)
|
2020-02-12 22:05:18 +00:00
|
|
|
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)
|
2020-02-16 00:03:12 +00:00
|
|
|
self.page_info_right_chev:enableDisable(self.cur_month < self.max_month or self.browse_future_months)
|
2020-02-12 22:05:18 +00:00
|
|
|
self.page_info_first_chev:enableDisable(self.cur_month > self.min_month)
|
2020-02-16 00:03:12 +00:00
|
|
|
self.page_info_last_chev:enableDisable(self.cur_month < self.max_month or self.browse_future_months)
|
2020-02-12 22:05:18 +00:00
|
|
|
|
|
|
|
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
|
2022-03-04 20:20:00 +00:00
|
|
|
local layout_row
|
2020-02-12 22:05:18 +00:00
|
|
|
while true do
|
|
|
|
cur_date = os.date("*t", cur_ts)
|
|
|
|
if cur_date.month ~= this_month then
|
|
|
|
break
|
|
|
|
end
|
2020-02-16 00:03:12 +00:00
|
|
|
if not cur_week or cur_date.wday == self.start_day_of_week then
|
2020-02-12 22:05:18 +00:00
|
|
|
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,
|
2020-02-16 00:03:12 +00:00
|
|
|
histo_shown = self.show_hourly_histogram,
|
2020-02-12 22:05:18 +00:00
|
|
|
span_height = self.span_height,
|
2020-02-16 00:03:12 +00:00
|
|
|
font_face = self.font_face,
|
2020-02-12 22:05:18 +00:00
|
|
|
font_size = self.span_font_size,
|
|
|
|
show_parent = self,
|
|
|
|
}
|
2022-03-04 20:20:00 +00:00
|
|
|
layout_row = {}
|
|
|
|
table.insert(self.layout, layout_row)
|
2020-02-12 22:05:18 +00:00
|
|
|
table.insert(self.weeks, cur_week)
|
|
|
|
table.insert(self.main_content, cur_week)
|
2020-02-16 00:03:12 +00:00
|
|
|
if cur_date.wday ~= self.start_day_of_week then
|
2020-02-12 22:05:18 +00:00
|
|
|
-- Add fake days to fill week
|
2020-02-16 00:03:12 +00:00
|
|
|
local day = self.start_day_of_week
|
2020-02-12 22:05:18 +00:00
|
|
|
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_ts = os.time({
|
|
|
|
year = cur_date.year,
|
|
|
|
month = cur_date.month,
|
|
|
|
day = cur_date.day,
|
|
|
|
hour = 0,
|
|
|
|
})
|
2020-02-16 00:03:12 +00:00
|
|
|
local is_future = day_s > today_s
|
2022-03-04 20:20:00 +00:00
|
|
|
local calendar_day = CalendarDay:new{
|
2020-02-16 00:03:12 +00:00
|
|
|
show_histo = self.show_hourly_histogram,
|
2020-02-12 22:05:18 +00:00
|
|
|
histo_height = self.span_height,
|
2020-02-16 00:03:12 +00:00
|
|
|
font_face = self.font_face,
|
2020-02-12 22:05:18 +00:00
|
|
|
font_size = self.span_font_size,
|
|
|
|
border = self.day_border,
|
2020-02-16 00:03:12 +00:00
|
|
|
is_future = is_future,
|
2020-02-12 22:05:18 +00:00
|
|
|
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,
|
2020-02-16 00:03:12 +00:00
|
|
|
callback = not is_future and function()
|
2022-11-22 19:55:27 +00:00
|
|
|
UIManager:show(CalendarDayView:new{
|
2023-04-01 17:15:36 +00:00
|
|
|
day_ts = day_ts + (self.reader_statistics.settings.calendar_day_start_hour or 0) * 3600
|
|
|
|
+ (self.reader_statistics.settings.calendar_day_start_minute or 0) * 60,
|
2022-11-22 19:55:27 +00:00
|
|
|
reader_statistics = self.reader_statistics,
|
|
|
|
close_callback = function(this)
|
2022-01-31 18:18:37 +00:00
|
|
|
-- Refresh calendar in case some day stats were reset for some books
|
|
|
|
-- (we don't know if some reset were done... so we refresh the current
|
|
|
|
-- display always - at tickAfterNext so there is no noticable slowness
|
|
|
|
-- when closing, and the re-painting happening after is not noticable;
|
|
|
|
-- but if some stat reset were done, this will make a nice noticable
|
|
|
|
-- repainting showing dynamically reset books disappearing :)
|
2022-11-22 19:55:27 +00:00
|
|
|
UIManager:tickAfterNext(function()
|
|
|
|
self:goToMonth(os.date("%Y-%m", this.day_ts + 10800))
|
|
|
|
end)
|
2022-01-31 18:18:37 +00:00
|
|
|
end,
|
2022-11-22 19:55:27 +00:00
|
|
|
min_month = self.min_month
|
2020-02-12 22:05:18 +00:00
|
|
|
})
|
|
|
|
end
|
2022-03-04 20:20:00 +00:00
|
|
|
}
|
|
|
|
cur_week:addDay(calendar_day)
|
|
|
|
table.insert(layout_row, calendar_day)
|
2020-02-12 22:05:18 +00:00
|
|
|
cur_ts = cur_ts + 86400 -- add one day
|
|
|
|
end
|
|
|
|
for _, week in ipairs(self.weeks) do
|
|
|
|
week:update()
|
|
|
|
end
|
2022-03-04 20:20:00 +00:00
|
|
|
self:moveFocusTo(1, 1, FocusManager.NOT_UNFOCUS)
|
2020-02-12 22:05:18 +00:00
|
|
|
UIManager:setDirty(self, function()
|
|
|
|
return "ui", self.dimen
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2023-04-07 07:02:23 +00:00
|
|
|
function CalendarView:showCalendarDayView(reader_statistics)
|
2022-11-22 19:55:27 +00:00
|
|
|
local date = os.date("*t", os.time())
|
2023-04-07 07:02:23 +00:00
|
|
|
if date.hour * 3600 + date.min * 60 + date.sec < (reader_statistics.settings.calendar_day_start_hour or 0) * 3600
|
|
|
|
+ (reader_statistics.settings.calendar_day_start_minute or 0) * 60 then
|
|
|
|
-- Should still be in previous day's timeline
|
|
|
|
date = os.date("*t", os.time() - 86400 + 10800) -- make sure it's the previous day
|
|
|
|
end
|
2022-11-22 19:55:27 +00:00
|
|
|
UIManager:show(CalendarDayView:new{
|
2023-04-01 17:15:36 +00:00
|
|
|
day_ts = os.time({ year = date.year, month = date.month, day = date.day, hour = reader_statistics.settings.calendar_day_start_hour or 0, min = reader_statistics.settings.calendar_day_start_minute or 0 }),
|
2022-11-22 19:55:27 +00:00
|
|
|
reader_statistics = reader_statistics,
|
|
|
|
min_month = self.min_month
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2020-02-12 22:05:18 +00:00
|
|
|
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)
|
2020-02-16 00:03:12 +00:00
|
|
|
if self.browse_future_months or next_month <= self.max_month then
|
2020-02-12 22:05:18 +00:00
|
|
|
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
|
|
|
|
|
2022-01-25 14:24:06 +00:00
|
|
|
function CalendarView:onMultiSwipe(arg, ges_ev)
|
|
|
|
-- For consistency with other fullscreen widgets where swipe south can't be
|
|
|
|
-- used to close and where we then allow any multiswipe to close, allow any
|
|
|
|
-- multiswipe to close this widget too.
|
|
|
|
self:onClose()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2020-02-12 22:05:18 +00:00
|
|
|
function CalendarView:onClose()
|
|
|
|
UIManager:close(self)
|
2022-11-22 19:55:27 +00:00
|
|
|
-- Remove ghosting
|
|
|
|
UIManager:setDirty(nil, "full")
|
2020-02-12 22:05:18 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return CalendarView
|