Add pomodoro plugin (port from legacy v4 plugin) (#69)
* add pomodoro plugin * add thumbnail.webp * fix translations * fix translation key * add required sections to README, add deps field to manifest * small fixes * fix config keys * review fixes * fix(readme) typos --------- Co-authored-by: Kirill Sergeev <sergeev@ap-team.ru> Co-authored-by: Lemmy <studio@quadbyte.net>
This commit is contained in:
co-authored by
Kirill Sergeev
Lemmy
parent
12532101dd
commit
144e7209ca
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Kirill Sergeev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Pomodoro Timer
|
||||
|
||||
A Pomodoro timer plugin for Noctalia for productivity. Initially ported from the legacy v4 plugin [Pomodoro Timer](https://github.com/noctalia-dev/legacy-v4-plugins/tree/main/pomodoro).
|
||||
|
||||
## Features
|
||||
- **Sessions**: Configurable sessions based on the standard format (work - short break - long break). Durations can be configured in the settings.
|
||||
- **Cycles**: Configurable number of (work - short break) cycles before a long break.
|
||||
- **Auto-start**: Optionally auto-start breaks and/or work sessions.
|
||||
- **Bar Widget**: Shows status and remaining time on the bar widget when the panel is closed.
|
||||
- **Notifications**: Toast notification when work/break finishes.
|
||||
|
||||
## TODO
|
||||
- Sound notification (currently the toast is shown silently)
|
||||
- IPC
|
||||
|
||||
## Plugin
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| ID | `thepunkoff/pomodoro` |
|
||||
| Entries | Bar widget: `widget`; panel: `panel`; service: `pomodoro` |
|
||||
|
||||
## Usage
|
||||
1. Enable plugin in settings
|
||||
2. Add bar widget `Pomodoro Timer`
|
||||
3. Widget appears on the bar, clicking it will toggle the panel.
|
||||
|
||||
To open the panel with a command:
|
||||
```sh
|
||||
noctalia msg panel-toggle thepunkoff/pomodoro:panel
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `work-duration` | `int` | `25` | Duration of each work session in minutes. |
|
||||
| `short-break-duration` | `int` | `5` | Duration of short breaks in minutes. |
|
||||
| `long-break-duration` | `int` | `15` | Duration of long breaks in minutes. |
|
||||
| `sessions-before-long-break` | `int` | `4` | Number of sessions before a long break (min=1). |
|
||||
| `auto-start-work` | `bool` | `false` | Automatically start the work timer after a break. |
|
||||
| `auto-start-breaks` | `bool` | `false` | Automatically start the break timer after a work session. |
|
||||
|
||||
## IPC
|
||||
```sh
|
||||
noctalia msg panel-toggle thepunkoff/pomodoro:panel
|
||||
```
|
||||
|
||||
## Licensing
|
||||
|
||||
This project is licensed under the MIT License.
|
||||
|
||||
It bundles the JetBrains Mono font, which is licensed separately under the SIL Open Font License 1.1 (OFL-1.1). See `THIRD_PARTY_LICENCES/OFL.txt` for the full license text.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,178 @@
|
||||
local timeFontFamily = noctalia.loadFont("JetBrainsMono-Regular.ttf")
|
||||
|
||||
local function formatTime(seconds, total)
|
||||
local showingHours = total >= 3600 or seconds >= 3600
|
||||
local hours = math.floor(seconds / 3600)
|
||||
local mins = math.floor((seconds % 3600) / 60)
|
||||
local secs = seconds % 60
|
||||
|
||||
if showingHours then
|
||||
return string.format("%d:%02d:%02d", hours, mins, secs)
|
||||
else
|
||||
return string.format("%02d:%02d", mins, secs)
|
||||
end
|
||||
end
|
||||
|
||||
function onStartButtonClick()
|
||||
noctalia.state.set("pomodoro.nextCommand", "toggle")
|
||||
end
|
||||
|
||||
function onSkipButtonClick()
|
||||
noctalia.state.set("pomodoro.nextCommand", "skip")
|
||||
end
|
||||
|
||||
function onResetButtonClick()
|
||||
noctalia.state.set("pomodoro.nextCommand", "reset")
|
||||
end
|
||||
|
||||
function onResetAllButtonClick()
|
||||
noctalia.state.set("pomodoro.nextCommand", "resetAll")
|
||||
end
|
||||
|
||||
local function render(state, sessionData)
|
||||
local sessionNumber = state.sessionPtr.session
|
||||
local session = sessionData[sessionNumber]
|
||||
local stageNumber = state.sessionPtr.stage
|
||||
local stageTotalSeconds = session[stageNumber]
|
||||
|
||||
local stageName =
|
||||
if stageNumber == 1 then
|
||||
noctalia.tr("work")
|
||||
else if sessionNumber < #sessionData then
|
||||
noctalia.tr("short-break")
|
||||
else
|
||||
noctalia.tr("long-break")
|
||||
|
||||
local startButtonText =
|
||||
if state.isRunning then
|
||||
noctalia.tr("button.pause")
|
||||
else if state.secondsLeft > 0 and state.secondsLeft < stageTotalSeconds then
|
||||
noctalia.tr("button.resume")
|
||||
else
|
||||
noctalia.tr("button.start")
|
||||
|
||||
local startButtonGlyph = if state.isRunning then "player-pause" else "player-play"
|
||||
|
||||
local skipButtonEnabled = state.isDirty and (if state.isRunning then state.secondsLeft > 0 else stageTotalSeconds > 0)
|
||||
|
||||
local resetButtonEnabled = state.isDirty and state.secondsLeft > 0
|
||||
|
||||
local resetAllButtonEnabled = state.isDirty and (state.isRunning or state.secondsLeft > 0 or (state.sessionPtr.session > 1 and state.sessionPtr.stage > 1))
|
||||
|
||||
local stageIcon = if state.sessionPtr.stage == 1 then "brain" else "coffee"
|
||||
|
||||
panel.render(
|
||||
ui.column({ flexGrow = 1, gap = 16 }, {
|
||||
-- header
|
||||
ui.row({ align = "center", gap = 8 }, {
|
||||
ui.glyph({ name = stageIcon, color = "primary" }),
|
||||
|
||||
ui.label({
|
||||
text = "Pomodoro",
|
||||
fontSize = 18,
|
||||
fontWeight = "bold",
|
||||
color = "on_surface",
|
||||
flexGrow = 1,
|
||||
}),
|
||||
|
||||
ui.label({
|
||||
text = string.format("%s %d/%d", noctalia.tr("session"), sessionNumber, #sessionData),
|
||||
fontSize = 12,
|
||||
color = "on_surface_variant",
|
||||
}),
|
||||
}),
|
||||
|
||||
-- time
|
||||
ui.column({ flexGrow = 1, align = "center", justify = "center", }, {
|
||||
ui.label({
|
||||
text = stageName,
|
||||
fontSize = 18,
|
||||
fontWeight = "medium",
|
||||
color = "primary",
|
||||
}),
|
||||
|
||||
ui.label({
|
||||
text = formatTime(state.secondsLeft, stageTotalSeconds),
|
||||
fontSize = 42,
|
||||
fontWeight = "bold",
|
||||
fontFamily = timeFontFamily,
|
||||
color = "primary",
|
||||
}),
|
||||
}),
|
||||
|
||||
-- buttons
|
||||
ui.column({ gap = 8 }, {
|
||||
ui.row({ gap = 8, justify = "space_between" }, {
|
||||
ui.button({
|
||||
variant = "primary",
|
||||
text = startButtonText,
|
||||
glyph = startButtonGlyph,
|
||||
onClick = "onStartButtonClick",
|
||||
flexGrow = 1,
|
||||
}),
|
||||
|
||||
ui.button({
|
||||
text = noctalia.tr("button.skip"),
|
||||
glyph = "player-skip-forward",
|
||||
onClick = "onSkipButtonClick",
|
||||
enabled = skipButtonEnabled,
|
||||
flexGrow = 1,
|
||||
}),
|
||||
}),
|
||||
|
||||
ui.row({ gap = 8, justify = "space_between" }, {
|
||||
ui.button({
|
||||
text = noctalia.tr("button.reset"),
|
||||
glyph = "refresh",
|
||||
onClick = "onResetButtonClick",
|
||||
enabled = resetButtonEnabled,
|
||||
flexGrow = 1,
|
||||
}),
|
||||
|
||||
ui.button({
|
||||
text = noctalia.tr("button.reset-all"),
|
||||
glyph = "rotate",
|
||||
onClick = "onResetAllButtonClick",
|
||||
enabled = resetAllButtonEnabled,
|
||||
flexGrow = 1,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}) -- column
|
||||
) -- panel
|
||||
end
|
||||
|
||||
function onOpen(context)
|
||||
local state = noctalia.state.get("pomodoro.state")
|
||||
local sessionData = noctalia.state.get("pomodoro.sessionData")
|
||||
render(state, sessionData)
|
||||
end
|
||||
|
||||
local function notifyStageFinished(state, sessionData)
|
||||
local sessionNumber = state.sessionPtr.session
|
||||
local stageNumber = state.sessionPtr.stage
|
||||
local body =
|
||||
if stageNumber == 1 then
|
||||
noctalia.tr("notification.work-complete")
|
||||
elseif sessionNumber < #sessionData then
|
||||
noctalia.tr("notification.short-break-complete")
|
||||
else
|
||||
noctalia.tr("notification.long-break-complete")
|
||||
noctalia.notify("Pomodoro Timer", body)
|
||||
end
|
||||
|
||||
--- main
|
||||
noctalia.state.watch("pomodoro.state", function(state)
|
||||
local config = noctalia.state.get("pomodoro.config")
|
||||
local sessionData = noctalia.state.get("pomodoro.sessionData")
|
||||
|
||||
if state.secondsLeft == 0 then
|
||||
notifyStageFinished(state, sessionData)
|
||||
noctalia.state.set("pomodoro.nextCommand", "skip")
|
||||
if (config.autoStartWork and state.sessionPtr.stage == 2) or (config.autoStartBreaks and state.sessionPtr.stage == 1) then
|
||||
noctalia.state.set("pomodoro.nextCommand", "toggle")
|
||||
end
|
||||
end
|
||||
|
||||
render(state, sessionData)
|
||||
end)
|
||||
@@ -0,0 +1,69 @@
|
||||
id = "thepunkoff/pomodoro"
|
||||
name = "Pomodoro Timer"
|
||||
version = "1.0.0"
|
||||
plugin_api = 3
|
||||
author = "thepunkoff"
|
||||
license = "MIT"
|
||||
icon = "brain"
|
||||
description = "Simple pomodoro timer."
|
||||
tags = ["bar", "panel", "service", "productivity", "time"]
|
||||
dependencies = []
|
||||
|
||||
[[setting]]
|
||||
key = "work-duration"
|
||||
type = "int"
|
||||
label_key = "settings.work-duration.label"
|
||||
description_key = "settings.work-duration.description"
|
||||
default = 25
|
||||
|
||||
[[setting]]
|
||||
key = "short-break-duration"
|
||||
type = "int"
|
||||
label_key = "settings.short-break-duration.label"
|
||||
description_key = "settings.short-break-duration.description"
|
||||
default = 5
|
||||
|
||||
[[setting]]
|
||||
key = "long-break-duration"
|
||||
type = "int"
|
||||
label_key = "settings.long-break-duration.label"
|
||||
description_key = "settings.long-break-duration.description"
|
||||
default = 15
|
||||
|
||||
[[setting]]
|
||||
key = "sessions-before-long-break"
|
||||
type = "int"
|
||||
label_key = "settings.sessions-before-long-break.label"
|
||||
description_key = "settings.sessions-before-long-break.description"
|
||||
default = 4
|
||||
min = 1
|
||||
|
||||
[[setting]]
|
||||
key = "auto-start-breaks"
|
||||
type = "bool"
|
||||
label_key = "settings.auto-start-breaks.label"
|
||||
description_key = "settings.auto-start-breaks.description"
|
||||
default = false
|
||||
|
||||
[[setting]]
|
||||
key = "auto-start-work"
|
||||
type = "bool"
|
||||
label_key = "settings.auto-start-work.label"
|
||||
description_key = "settings.auto-start-work.description"
|
||||
default = false
|
||||
|
||||
[[widget]]
|
||||
id = "widget"
|
||||
entry = "widget.luau"
|
||||
|
||||
[[panel]]
|
||||
id = "panel"
|
||||
entry = "panel.luau"
|
||||
placement = "attached"
|
||||
open_near_click = true
|
||||
width = 350
|
||||
height = 250
|
||||
|
||||
[[service]]
|
||||
id = "pomodoro"
|
||||
entry = "pomodoro.luau"
|
||||
@@ -0,0 +1,83 @@
|
||||
local config = (function()
|
||||
return {
|
||||
workDuration = noctalia.getConfig("work-duration"),
|
||||
shortBreakDuration = noctalia.getConfig("short-break-duration"),
|
||||
longBreakDuration = noctalia.getConfig("long-break-duration"),
|
||||
sessionsBeforeLongBreak = noctalia.getConfig("sessions-before-long-break"),
|
||||
autoStartBreaks = noctalia.getConfig("auto-start-breaks"),
|
||||
autoStartWork = noctalia.getConfig("auto-start-work"),
|
||||
}
|
||||
end)()
|
||||
noctalia.state.set("pomodoro.config", config)
|
||||
|
||||
local sessionData = {}
|
||||
for i = 1, config.sessionsBeforeLongBreak do
|
||||
breakDuration = if i < config.sessionsBeforeLongBreak then config.shortBreakDuration else config.longBreakDuration
|
||||
table.insert(sessionData, { config.workDuration * 60, breakDuration * 60 })
|
||||
end
|
||||
noctalia.state.set("pomodoro.sessionData", sessionData)
|
||||
|
||||
local isRunning = false
|
||||
local sessionPtr = { session = 1, stage = 1 }
|
||||
local isDirty = false
|
||||
local secondsLeft = 0
|
||||
|
||||
local function getStateSnapshot()
|
||||
return {
|
||||
isRunning = isRunning,
|
||||
secondsLeft = secondsLeft,
|
||||
sessionPtr = sessionPtr,
|
||||
isDirty = isDirty,
|
||||
}
|
||||
end
|
||||
|
||||
local function getStageTotalSeconds()
|
||||
local sessionNumber = sessionPtr.session
|
||||
local session = sessionData[sessionNumber]
|
||||
local stageNumber = sessionPtr.stage
|
||||
return session[stageNumber]
|
||||
end
|
||||
|
||||
--- main
|
||||
secondsLeft = getStageTotalSeconds()
|
||||
|
||||
noctalia.state.watch("pomodoro.nextCommand", function(command)
|
||||
if command == "toggle" then
|
||||
isDirty = true
|
||||
isRunning = not isRunning
|
||||
elseif command == "skip" then
|
||||
isRunning = false
|
||||
if sessionPtr.stage == 1 then
|
||||
sessionPtr.stage = 2
|
||||
elseif sessionPtr.session < #sessionData then
|
||||
sessionPtr.session += 1
|
||||
sessionPtr.stage = 1
|
||||
elseif sessionPtr.session == #sessionData then
|
||||
sessionPtr = { session = 1, stage = 1 }
|
||||
end
|
||||
secondsLeft = getStageTotalSeconds()
|
||||
elseif command == "reset" then
|
||||
isRunning = false
|
||||
secondsLeft = getStageTotalSeconds()
|
||||
elseif command == "resetAll" then
|
||||
isRunning = false
|
||||
sessionPtr = { session = 1, stage = 1 }
|
||||
secondsLeft = getStageTotalSeconds()
|
||||
isDirty = false
|
||||
end
|
||||
|
||||
local state = getStateSnapshot()
|
||||
noctalia.state.set("pomodoro.state", state)
|
||||
end)
|
||||
|
||||
local state = getStateSnapshot()
|
||||
noctalia.state.set("pomodoro.state", state)
|
||||
|
||||
noctalia.setUpdateInterval(1000)
|
||||
function update()
|
||||
if isRunning then
|
||||
secondsLeft -= 1
|
||||
local state = getStateSnapshot()
|
||||
noctalia.state.set("pomodoro.state", state)
|
||||
end
|
||||
end
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"work": "Work",
|
||||
"short-break": "Short Break",
|
||||
"long-break": "Long Break",
|
||||
"session": "Session",
|
||||
"button": {
|
||||
"start": "Start",
|
||||
"resume": "Resume",
|
||||
"pause": "Pause",
|
||||
"skip": "Skip",
|
||||
"reset": "Reset",
|
||||
"reset-all": "Reset All"
|
||||
},
|
||||
"notification": {
|
||||
"work-complete": "Work session complete! Time for a break.",
|
||||
"short-break-complete": "Break over! Ready to focus?",
|
||||
"long-break-complete": "Long break over! Ready for a new cycle?"
|
||||
},
|
||||
"settings": {
|
||||
"work-duration":{
|
||||
"label": "Work Duration",
|
||||
"description": "Duration of each work session in minutes"
|
||||
},
|
||||
"short-break-duration":{
|
||||
"label": "Short Break Duration",
|
||||
"description": "Duration of short breaks in minutes"
|
||||
},
|
||||
"long-break-duration":{
|
||||
"label": "Long Break Duration",
|
||||
"description": "Duration of long breaks in minutes"
|
||||
},
|
||||
"sessions-before-long-break":{
|
||||
"label": "Sessions Before Long Break",
|
||||
"description": "Number of sessions before a long break"
|
||||
},
|
||||
"auto-start-work":{
|
||||
"label": "Auto-start Work",
|
||||
"description": "Automatically start work timer after break"
|
||||
},
|
||||
"auto-start-breaks":{
|
||||
"label": "Auto-start Breaks",
|
||||
"description": "Automatically start break timer after work session"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
function onClick()
|
||||
noctalia.togglePanel("thepunkoff/pomodoro:panel")
|
||||
end
|
||||
|
||||
local isUpdating = false
|
||||
noctalia.state.watch("pomodoro.nextCommand", function(command)
|
||||
if command == "toggle" then
|
||||
isUpdating = true
|
||||
elseif command == "resetAll" then
|
||||
isUpdating = false
|
||||
barWidget.setGlyph("brain")
|
||||
barWidget.setGlyphColor("default")
|
||||
barWidget.setColor("default")
|
||||
barWidget.setText("")
|
||||
end
|
||||
end)
|
||||
|
||||
--- main
|
||||
barWidget.setGlyph("brain")
|
||||
|
||||
noctalia.state.watch("pomodoro.state", function(state)
|
||||
if not isUpdating then
|
||||
return
|
||||
end
|
||||
|
||||
local stageIcon = if state.sessionPtr.stage == 1 then "brain" else "coffee"
|
||||
barWidget.setGlyph(stageIcon)
|
||||
|
||||
if state.isRunning then
|
||||
barWidget.setGlyphColor("primary")
|
||||
barWidget.setColor("primary")
|
||||
else
|
||||
barWidget.setGlyphColor("default")
|
||||
barWidget.setColor("default")
|
||||
end
|
||||
|
||||
local hours = math.floor(state.secondsLeft / 3600)
|
||||
local mins = math.floor((state.secondsLeft % 3600) / 60)
|
||||
local secs = state.secondsLeft % 60
|
||||
|
||||
local time = if hours == 0 then string.format("%02d:%02d", mins, secs) else string.format("%d:%02d:%02d", hours, mins, secs)
|
||||
barWidget.setText(time)
|
||||
end)
|
||||
Reference in New Issue
Block a user