2
0
mirror of https://github.com/koreader/koreader synced 2024-11-10 01:10:34 +00:00
koreader/frontend/ui/widget/bookstatuswidget.lua

546 lines
15 KiB
Lua
Raw Normal View History

2017-04-29 08:38:09 +00:00
local Blitbuffer = require("ffi/blitbuffer")
local Button = require("ui/widget/button")
2016-02-02 17:38:14 +00:00
local CenterContainer = require("ui/widget/container/centercontainer")
2017-04-29 08:38:09 +00:00
local CloseButton = require("ui/widget/closebutton")
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
2016-02-02 17:38:14 +00:00
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
2017-04-29 08:38:09 +00:00
local ImageWidget = require("ui/widget/imagewidget")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
2016-02-02 17:38:14 +00:00
local InputText = require("ui/widget/inputtext")
2017-04-29 08:38:09 +00:00
local LeftContainer = require("ui/widget/container/leftcontainer")
2016-02-02 17:38:14 +00:00
local LineWidget = require("ui/widget/linewidget")
2017-04-29 08:38:09 +00:00
local OverlapGroup = require("ui/widget/overlapgroup")
local ProgressWidget = require("ui/widget/progresswidget")
2016-02-09 12:51:55 +00:00
local TextBoxWidget = require("ui/widget/textboxwidget")
2017-04-29 08:38:09 +00:00
local TextWidget = require("ui/widget/textwidget")
local TimeVal = require("ui/timeval")
local ToggleSwitch = require("ui/widget/toggleswitch")
2016-02-02 17:38:14 +00:00
local UIManager = require("ui/uimanager")
2017-04-29 08:38:09 +00:00
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
2016-02-02 17:38:14 +00:00
local Screen = require("device").screen
local template = require("ffi/util").template
2016-02-02 17:38:14 +00:00
local util = require("util")
local _ = require("gettext")
2017-09-14 20:29:09 +00:00
local stats_book = {}
2016-02-02 17:38:14 +00:00
--[[
--Save into sdr folder addtional section
["summary"] = {
["rating"] = 5,
["note"] = "Some text",
["status"] = "Reading"
["modified"] = "24.01.2016"
},]]
local BookStatusWidget = InputContainer:new{
padding = Screen:scaleBySize(15),
2016-02-02 17:38:14 +00:00
settings = nil,
thumbnail = nil,
props = nil,
star = {},
summary = {
rating = nil,
note = nil,
status = "",
modified = "",
},
}
function BookStatusWidget:init()
2016-02-02 17:38:14 +00:00
if self.settings then
self.summary = self.settings:readSetting("summary") or {
rating = nil,
note = nil,
status = "",
modified = "",
}
2016-02-02 17:38:14 +00:00
end
2017-09-14 20:29:09 +00:00
self.total_pages = self.view.document:getPageCount()
stats_book = self:getStats()
2016-02-02 17:38:14 +00:00
2017-04-29 08:38:09 +00:00
self.small_font_face = Font:getFace("smallffont")
self.medium_font_face = Font:getFace("ffont")
self.large_font_face = Font:getFace("largeffont")
2016-02-02 17:38:14 +00:00
2016-02-10 07:01:19 +00:00
self.star = Button:new{
2016-02-02 17:38:14 +00:00
icon = "resources/icons/stats.star.empty.png",
bordersize = 0,
radius = 0,
margin = 0,
enabled = true,
show_parent = self,
}
local screen_size = Screen:getSize()
self[1] = FrameContainer:new{
width = screen_size.w,
height = screen_size.h,
2016-02-02 17:38:14 +00:00
background = Blitbuffer.COLOR_WHITE,
bordersize = 0,
padding = 0,
self:getStatusContent(screen_size.w),
2016-02-02 17:38:14 +00:00
}
end
2017-09-14 20:29:09 +00:00
function BookStatusWidget:getStats()
return {}
end
function BookStatusWidget:getStatDays()
if stats_book.days then
return stats_book.days
else
return _("N/A")
end
end
function BookStatusWidget:getStatHours()
if stats_book.time then
return util.secondsToClock(stats_book.time, false)
else
return _("N/A")
end
end
function BookStatusWidget:getStatReadPages()
if stats_book.pages then
return string.format("%s/%s",stats_book.pages, self.total_pages)
else
return _("N/A")
end
end
function BookStatusWidget:getStatusContent(width)
return VerticalGroup:new{
align = "left",
OverlapGroup:new{
dimen = Geom:new{ w = width, h = Screen:scaleBySize(30) },
CloseButton:new{ window = self },
},
self:genBookInfoGroup(),
self:genHeader(_("Statistics")),
self:genStatisticsGroup(width),
self:genHeader(_("Review")),
self:genSummaryGroup(width),
self:genHeader(_("Update Status")),
self:generateSwitchGroup(width),
2016-02-02 17:38:14 +00:00
}
end
function BookStatusWidget:genHeader(title)
local width, height = Screen:getWidth(), Screen:scaleBySize(35)
2016-02-02 17:38:14 +00:00
local header_title = TextWidget:new{
2016-02-02 17:38:14 +00:00
text = title,
face = self.medium_font_face,
fgcolor = Blitbuffer.gray(0.4),
2016-02-02 17:38:14 +00:00
}
local padding_span = HorizontalSpan:new{ width = self.padding }
local line_width = (width - header_title:getSize().w) / 2 - self.padding * 2
2016-02-10 07:01:19 +00:00
local line_container = LeftContainer:new{
dimen = Geom:new{ w = line_width, h = height },
2016-02-10 07:01:19 +00:00
LineWidget:new{
2016-02-02 17:38:14 +00:00
background = Blitbuffer.gray(0.2),
2016-02-10 07:01:19 +00:00
dimen = Geom:new{
w = line_width,
2016-02-02 17:38:14 +00:00
h = 2,
}
}
}
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(25) },
HorizontalGroup:new{
align = "center",
padding_span,
line_container,
padding_span,
header_title,
padding_span,
line_container,
padding_span,
2016-02-02 17:38:14 +00:00
},
VerticalSpan:new{ width = Screen:scaleBySize(5) },
2016-02-02 17:38:14 +00:00
}
end
function BookStatusWidget:onChangeBookStatus(option_name, option_value)
2016-02-02 17:38:14 +00:00
local curr_time = TimeVal:now()
self.summary.status = option_name[option_value]
self.summary.modified = os.date("%Y-%m-%d", curr_time.sec)
self:saveSummary()
return true
end
function BookStatusWidget:generateRateGroup(width, height, rating)
2016-02-10 07:01:19 +00:00
self.stars_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
2016-02-02 17:38:14 +00:00
}
self:setStar(rating)
return self.stars_container
end
function BookStatusWidget:setStar(num)
2016-02-02 17:38:14 +00:00
--clear previous data
self.stars_container:clear()
2016-02-10 07:01:19 +00:00
local stars_group = HorizontalGroup:new{ align = "center" }
2016-02-02 17:38:14 +00:00
if num then
self.summary.rating = num
self:saveSummary()
for i = 1, num do
2016-02-10 07:01:19 +00:00
table.insert(stars_group, self.star:new{
icon = "resources/icons/stats.star.full.png",
callback = function() self:setStar(i) end
})
2016-02-02 17:38:14 +00:00
end
else
num = 0
end
for i = num + 1, 5 do
2016-02-10 07:01:19 +00:00
table.insert(stars_group, self.star:new{ callback = function() self:setStar(i) end })
2016-02-02 17:38:14 +00:00
end
table.insert(self.stars_container, stars_group)
UIManager:setDirty(nil, "partial")
return true
end
function BookStatusWidget:genBookInfoGroup()
local screen_width = Screen:getWidth()
local split_span_width = screen_width * 0.05
local img_width, img_height
if Screen:getScreenMode() == "landscape" then
img_width = Screen:scaleBySize(132)
img_height = Screen:scaleBySize(184)
else
img_width = Screen:scaleBySize(132 * 1.5)
img_height = Screen:scaleBySize(184 * 1.5)
end
local height = img_height
local width = screen_width - split_span_width - img_width
-- title
local book_meta_info_group = VerticalGroup:new{
align = "center",
VerticalSpan:new{ width = height * 0.2 },
TextBoxWidget:new{
text = self.props.title,
width = width,
face = self.medium_font_face,
alignment = "center",
},
}
-- author
local text_author = TextWidget:new{
text = self.props.authors,
face = self.small_font_face,
padding = 2,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_author:getSize().h },
text_author
}
)
-- progress bar
2017-09-14 20:29:09 +00:00
local read_percentage = self.view.state.page / self.total_pages
local progress_bar = ProgressWidget:new{
width = width * 0.7,
height = Screen:scaleBySize(10),
percentage = read_percentage,
2016-04-21 03:48:50 +00:00
ticks = nil,
last = nil,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = progress_bar:getSize().h },
progress_bar
}
)
-- complete text
local text_complete = TextWidget:new{
text = template(_("%1% Completed"),
string.format("%1.f", read_percentage * 100)),
face = self.small_font_face,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_complete:getSize().h },
text_complete
}
)
-- rating
table.insert(book_meta_info_group,
VerticalSpan:new{ width = Screen:scaleBySize(30) })
local rateHeight = Screen:scaleBySize(60)
table.insert(book_meta_info_group,
self:generateRateGroup(screen_width, rateHeight, self.summary.rating))
-- build the final group
local book_info_group = HorizontalGroup:new{
align = "top",
HorizontalSpan:new{ width = split_span_width }
}
-- thumbnail
if self.thumbnail then
table.insert(book_info_group, ImageWidget:new{
image = self.thumbnail,
width = img_width,
height = img_height,
})
2017-05-08 07:43:34 +00:00
-- dereference thumbnail since we let imagewidget manages its lifecycle
self.thumbnail = nil
end
table.insert(book_info_group, CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
book_meta_info_group,
})
return CenterContainer:new{
dimen = Geom:new{ w = screen_width, h = img_height },
book_info_group,
}
end
function BookStatusWidget:genStatisticsGroup(width)
local height = Screen:scaleBySize(60)
2016-02-10 07:01:19 +00:00
local statistics_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
2016-02-02 17:38:14 +00:00
}
2016-02-10 07:01:19 +00:00
local statistics_group = VerticalGroup:new{ align = "left" }
2016-02-02 17:38:14 +00:00
2016-02-09 12:51:55 +00:00
local tile_width = width / 3
local tile_height = height / 2
2016-02-02 17:38:14 +00:00
2016-02-10 07:01:19 +00:00
local titles_group = HorizontalGroup:new{
2016-02-09 12:51:55 +00:00
align = "center",
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2016-02-09 12:51:55 +00:00
text = _("Days"),
face = self.small_font_face,
},
2016-02-02 17:38:14 +00:00
},
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2016-02-09 12:51:55 +00:00
text = _("Time"),
face = self.small_font_face,
},
2016-02-02 17:38:14 +00:00
},
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2016-02-09 12:51:55 +00:00
text = _("Read pages"),
face = self.small_font_face,
}
2016-02-02 17:38:14 +00:00
}
}
2016-02-10 07:01:19 +00:00
local data_group = HorizontalGroup:new{
2016-02-09 12:51:55 +00:00
align = "center",
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2017-09-14 20:29:09 +00:00
text = self:getStatDays(),
2016-02-09 12:51:55 +00:00
face = self.medium_font_face,
},
2016-02-02 17:38:14 +00:00
},
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2017-09-14 20:29:09 +00:00
text = self:getStatHours(),
2016-02-09 12:51:55 +00:00
face = self.medium_font_face,
},
2016-02-02 17:38:14 +00:00
},
2016-02-10 07:01:19 +00:00
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
2017-09-14 20:29:09 +00:00
text = self:getStatReadPages(),
2016-02-09 12:51:55 +00:00
face = self.medium_font_face,
}
2016-02-02 17:38:14 +00:00
}
}
table.insert(statistics_group, titles_group)
table.insert(statistics_group, data_group)
table.insert(statistics_container, statistics_group)
return statistics_container
end
function BookStatusWidget:genSummaryGroup(width)
local height
if Screen:getScreenMode() == "landscape" then
height = Screen:scaleBySize(60)
else
height = Screen:scaleBySize(130)
end
2016-02-02 17:38:14 +00:00
local text_padding = 5
self.input_note = InputText:new{
text = self.summary.note,
face = self.medium_font_face,
width = width - self.padding * 3,
height = height * 0.75,
scroll = true,
bordersize = 2,
focused = false,
padding = text_padding,
parent = self,
hint = _("A few words about the book"),
2016-02-02 17:38:14 +00:00
}
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(5) },
CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
self.input_note
2016-02-02 17:38:14 +00:00
}
2016-02-09 12:51:55 +00:00
}
end
2016-02-02 17:38:14 +00:00
function BookStatusWidget:onUpdateNote()
self.summary.note = self.input_note:getText()
self:saveSummary()
return true
end
2016-02-02 17:38:14 +00:00
function BookStatusWidget:saveSummary()
if self.summary then
self.settings:saveSetting("summary", self.summary)
self.settings:flush()
end
end
2016-02-02 17:38:14 +00:00
function BookStatusWidget:generateSwitchGroup(width)
local height
if Screen:getScreenMode() == "landscape" then
-- landscape mode
height = Screen:scaleBySize(60)
else
-- portrait mode
height = Screen:scaleBySize(105)
end
local args = { "complete", "reading", "abandoned" }
local current_status = self.summary.status
local position = 2
for k, v in pairs(args) do
2016-03-07 06:47:24 +00:00
if v == current_status then
position = k
end
end
local config = {
event = "ChangeBookStatus",
default_value = 2,
args = args,
default_arg = "reading",
toggle = { _("Complete"), _("Reading"), _("Abandoned") },
values = { 1, 2, 3 },
name = "book_status",
alternate = false,
enabled = true,
2016-02-02 17:38:14 +00:00
}
local switch = ToggleSwitch:new{
width = width * 0.6,
default_value = config.default_value,
name = config.name,
name_text = config.name_text,
event = config.event,
toggle = config.toggle,
args = config.args,
alternate = config.alternate,
default_arg = config.default_arg,
values = config.values,
enabled = config.enable,
config = self,
2016-02-02 17:38:14 +00:00
}
switch:setPosition(position)
2016-02-02 17:38:14 +00:00
return VerticalGroup:new{
VerticalSpan:new{ width = Screen:scaleBySize(10) },
CenterContainer:new{
ignore = "height",
dimen = Geom:new{ w = width, h = height },
switch,
}
2016-02-02 17:38:14 +00:00
}
end
2016-02-02 17:38:14 +00:00
function BookStatusWidget:onConfigChoose(values, name, event, args, events, position)
UIManager:scheduleIn(0.05, function()
if values then
self:onChangeBookStatus(args, position)
end
UIManager:setDirty("all")
end)
2016-02-02 17:38:14 +00:00
end
function BookStatusWidget:onAnyKeyPressed()
2016-02-02 17:38:14 +00:00
return self:onClose()
end
function BookStatusWidget:onClose()
2016-02-02 17:38:14 +00:00
self:saveSummary()
UIManager:setDirty("all")
UIManager:close(self)
return true
end
function BookStatusWidget:onSwitchFocus(inputbox)
2016-02-10 07:01:19 +00:00
self.note_dialog = InputDialog:new{
2016-02-02 17:38:14 +00:00
title = "Note",
input = self.input_note:getText(),
input_hint = "",
input_type = "text",
scroll = true,
text_height = Screen:scaleBySize(150),
buttons = {
{
{
text = _("Cancel"),
callback = function()
self:closeInputDialog()
end,
},
{
text = _("OK"),
is_enter_default = true,
2016-02-02 17:38:14 +00:00
callback = function()
self.input_note:setText(self.note_dialog:getInputText())
self:closeInputDialog()
self:onUpdateNote()
end,
},
},
},
}
self.note_dialog:onShowKeyboard()
UIManager:show(self.note_dialog)
end
function BookStatusWidget:closeInputDialog()
2016-02-02 17:38:14 +00:00
UIManager:close(self.note_dialog)
end
return BookStatusWidget