-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbreakview.lua
More file actions
154 lines (139 loc) · 5.39 KB
/
Copy pathbreakview.lua
File metadata and controls
154 lines (139 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
local Blitbuffer = require("ffi/blitbuffer")
local ButtonTable = require("ui/widget/buttontable")
local CenterContainer = require("ui/widget/container/centercontainer")
local Device = require("device")
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local InputContainer = require("ui/widget/container/inputcontainer")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local Widget = require("ui/widget/widget")
local logic = require("breaklogic")
local _ = require("eyerest_l10n")
local T = require("ffi/util").template
local Screen = Device.screen
local POLL_INTERVAL = 10 -- 秒:粗轮询间隔(详见 spec §3.3)
local STAGES = 5
-- 5 等份整格进度条(整格点亮,墨水屏友好)。核心 ProgressWidget 填充是连续的,
-- 做不到整格,故自写 paintTo(参考 s4m-mo/pomodoro.koplugin)。
local SegBar = Widget:extend{
width = 0,
height = 0,
stages = STAGES,
current = 0,
}
function SegBar:getSize() return Geom:new{ w = self.width, h = self.height } end
function SegBar:paintTo(bb, x, y)
local fg = Blitbuffer.COLOR_BLACK
local border = Size.border.thick
bb:paintBorder(x, y, self.width, self.height, border, fg)
local seg_w = math.floor(self.width / self.stages)
for i = 1, self.stages do
local rx = x + (i - 1) * seg_w
if i <= self.current then
bb:paintRect(rx, y, seg_w, self.height, fg)
end
if i < self.stages then
bb:paintRect(rx + seg_w - border, y, border, self.height, fg)
end
end
end
local BreakView = InputContainer:extend{
break_type = "mini", -- "mini" | "long"
duration = 300, -- 秒
strict = false,
on_done = nil,
on_skip = nil,
on_postpone = nil,
}
function BreakView:init()
self.modal = true -- 输入只路由给本 widget,外部点击无效
self.covers_fullscreen = true
self.dimen = Screen:getSize()
self.started = os.time()
self.deadline = self.started + self.duration
-- 粗轮询,但对很短的休息(按秒设置)收紧到每个阶段边界,保证 5 格都能走到
self.poll_interval = math.max(1, math.min(POLL_INTERVAL, math.floor(self.duration / STAGES)))
local title_text = self.break_type == "long" and _("Long break") or _("Mini break")
self.bar = SegBar:new{
width = math.floor(Screen:getWidth() * 0.7),
height = Size.item.height_default,
stages = STAGES,
current = 0,
}
self.remaining_widget = TextWidget:new{
text = self:_remainText(self.duration),
face = Font:getFace("cfont", 20),
}
local vgroup = VerticalGroup:new{ align = "center" }
table.insert(vgroup, TextWidget:new{ text = title_text, face = Font:getFace("tfont", 28) })
table.insert(vgroup, VerticalSpan:new{ width = Size.padding.large })
table.insert(vgroup, self.bar)
table.insert(vgroup, VerticalSpan:new{ width = Size.padding.large })
table.insert(vgroup, self.remaining_widget)
table.insert(vgroup, VerticalSpan:new{ width = Size.padding.large })
if self.strict then
table.insert(vgroup, TextWidget:new{
text = _("Please rest your eyes."),
face = Font:getFace("cfont", 18),
})
else
table.insert(vgroup, ButtonTable:new{
buttons = {{
{ text = _("Skip"), callback = function() self:_finish("skip") end },
{ text = _("Read a bit more"), callback = function() self:_finish("postpone") end },
}},
show_parent = self,
})
end
self[1] = CenterContainer:new{
dimen = Screen:getSize(),
FrameContainer:new{
background = Blitbuffer.COLOR_WHITE,
bordersize = Size.border.window,
padding = Size.padding.large,
vgroup,
},
}
self._poll_cb = function() self:_poll() end
end
function BreakView:_remainText(remaining)
remaining = math.max(math.floor(remaining), 0)
return T(_("%1 left"), string.format("%d:%02d", math.floor(remaining / 60), remaining % 60))
end
function BreakView:onShow()
UIManager:setDirty(self, "full") -- 打开做一次全屏刷新清残影
UIManager:scheduleIn(self.poll_interval, self._poll_cb)
return true
end
function BreakView:_poll()
local now = os.time()
local remaining = self.deadline - now
if remaining <= 0 then
self:_finish("done")
return
end
local stage = logic.stageOf(now - self.started, self.duration, STAGES)
if stage ~= self.bar.current then
self.bar.current = stage
self.remaining_widget:setText(self:_remainText(remaining))
UIManager:setDirty(self, "ui") -- 仅阶段变化时局部刷新
end
UIManager:scheduleIn(self.poll_interval, self._poll_cb)
end
function BreakView:_finish(result)
UIManager:unschedule(self._poll_cb)
UIManager:close(self)
-- result is "skip" | "postpone" | "done"; on_done is the fallback
local cb = self["on_" .. result] or self.on_done
if cb then cb() end
end
function BreakView:onCloseWidget()
UIManager:unschedule(self._poll_cb)
UIManager:setDirty(nil, "flashpartial") -- 关闭清残影
end
return BreakView