Compare commits
2 commits
b60df1c025
...
cb6616f400
Author | SHA1 | Date | |
---|---|---|---|
cb6616f400 | |||
a0dba673a2 |
7 changed files with 109 additions and 86 deletions
52
README.md
52
README.md
|
@ -34,44 +34,42 @@ Here are the available commands:
|
||||||
| `pause` | Pauses the current session | `{"command": "pause", "password": ""}` |
|
| `pause` | Pauses the current session | `{"command": "pause", "password": ""}` |
|
||||||
| `resume` | Resumes a paused session | `{"command": "resume", "password": ""}` |
|
| `resume` | Resumes a paused session | `{"command": "resume", "password": ""}` |
|
||||||
| `reset` | Stops and resets the current session | `{"command": "reset", "password": ""}` |
|
| `reset` | Stops and resets the current session | `{"command": "reset", "password": ""}` |
|
||||||
|
| `updateSettings` | Update Pomodoro settings | `{"command": "updateSettings", "password": "", "settings": {"work": 600, "shortBreak": 60, "longBreak": 300, "sessions": 2}}` |
|
||||||
|
|
||||||
#### Optional Start Parameters
|
#### Update Settings Command (`updateSettings`)
|
||||||
|
|
||||||
The Start-Command may contain an optional Pomodoro-Config, which allows you to customize the length of the work session, short break, long break, and the number of sessions. If no configuration is provided, the server will use default values.
|
The `updateSettings` command allows clients to modify the Pomodoro timer configuration, including the length of work sessions, short breaks, long breaks, and the total number of sessions in a cycle. This command must include a valid password to be accepted by the server. The updateSettings command can be used when the timer is stopped.
|
||||||
|
|
||||||
Example:
|
- Fields in the `settings` Object:
|
||||||
```json
|
- `work`: Length of the work session (in seconds).
|
||||||
{
|
- `shortBreak`: Length of the short break (in seconds).
|
||||||
command: "start",
|
- `longBreak`: Length of the long break (in seconds).
|
||||||
password: "foobar",
|
- `sessions`: Total number of work/break sessions in the Pomodoro cycle.
|
||||||
config: {
|
|
||||||
"work": 10, // Length of the work session in seconds
|
All fields are mandatory and may not be ommitted.
|
||||||
"shortBreak": 5, // Length of the short break in seconds
|
|
||||||
"longBreak": 10, // Length of the long break in seconds
|
|
||||||
"sessions": 2 // Number of total sessions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server Messages
|
### Server Messages
|
||||||
|
|
||||||
The server periodically (every second) sends JSON-encoded messages to all connected clients to update them on the current state of the Pomodoro session.
|
The server periodically (every second) sends JSON-encoded messages to all connected clients to update them on the current state of the Pomodoro session. These messages contain the following fields:
|
||||||
These messages contain the following fields:
|
|
||||||
|
|
||||||
- mode: Indicates the current phase of the Pomodoro session ("Work", "ShortBreak", "LongBreak", or empty if no session is running).
|
- mode: Indicates the current phase of the Pomodoro session ("Work", "ShortBreak", "LongBreak", "End" or "Idle").
|
||||||
|
- settings: Contains the current Pomodoro settings:
|
||||||
|
- work: Length of the work session in seconds (e.g., 1500 for 25 minutes).
|
||||||
|
- shortBreak: Length of the short break in seconds (e.g., 300 for 5 minutes).
|
||||||
|
- longBreak: Length of the long break in seconds (e.g., 900 for 15 minutes).
|
||||||
|
- sessions: The total number of work/break sessions (e.g., 4).
|
||||||
- session: The current session number (e.g., 1 for the first work session).
|
- session: The current session number (e.g., 1 for the first work session).
|
||||||
- total_sessions: The total number of sessions for the current Pomodoro cycle (e.g., 4 if the cycle consists of 4 work/break sessions).
|
|
||||||
- time_left: The remaining time for the current mode, in seconds (e.g., 900 for 15 minutes).
|
- time_left: The remaining time for the current mode, in seconds (e.g., 900 for 15 minutes).
|
||||||
- ongoing: Wether a pomodoro is currently ongoing
|
- ongoing: Whether a Pomodoro session is currently ongoing.
|
||||||
- paused: Wether the timer is paused
|
- paused: Whether the timer is paused.
|
||||||
|
|
||||||
| Message Type | Example |
|
| Message Type | Example |
|
||||||
| --------------------- | --------------------------------------------------- |
|
| --- | --- |
|
||||||
| Welcome Message | `{"mode": "", "session":0, "total_sessions":0, "time_left":0, "ongoing": false, "paused": false}` |
|
| Welcome Message | {"mode":"Idle", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":1500, "ongoing":false, "paused":false} |
|
||||||
| Session Running | `{"mode": "Work", "session": 1, "total_sessions": 4, "time_left": 900, "ongoing": true, "paused": false}` |
|
| Session Running | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":1, "time_left":900, "ongoing":true, "paused":false} |
|
||||||
| Session Running | `{"mode": "ShortBreak", "session": 2, "total_sessions": 4, "time_left": 50, "ongoing": true, "paused": false}` |
|
| Session Running | {"mode":"ShortBreak", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":50, "ongoing":true, "paused":false} |
|
||||||
| Session Paused | `{"mode": "Work", "session": 2, "total_sessions": 4, "time_left": 456, "ongoing": true, "paused": true}` |
|
| Session Paused | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":456, "ongoing":true, "paused":true} |
|
||||||
| Session End/Reset | `{"mode": "", "session": 0, "total_sessions": 0, "time_left": 0, "ongoing": false, "paused": false}` |
|
| Session End/Reset | {"mode":"End", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":0, "ongoing":false, "paused":false} |
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|
28
index.html
28
index.html
|
@ -20,6 +20,13 @@
|
||||||
input {
|
input {
|
||||||
width: 75px;
|
width: 75px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings {
|
||||||
|
border: 2px solid black;
|
||||||
|
background: #e7e7e7;
|
||||||
|
padding: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -27,6 +34,7 @@
|
||||||
<h1>Pomodoro Timer</h1>
|
<h1>Pomodoro Timer</h1>
|
||||||
|
|
||||||
<!-- Input fields for custom Pomodoro config and control password -->
|
<!-- Input fields for custom Pomodoro config and control password -->
|
||||||
|
<div class="settings">
|
||||||
<p>
|
<p>
|
||||||
<label for="password">Control Password:</label>
|
<label for="password">Control Password:</label>
|
||||||
<input type="text" id="password" placeholder="Password" />
|
<input type="text" id="password" placeholder="Password" />
|
||||||
|
@ -43,7 +51,10 @@
|
||||||
<br />
|
<br />
|
||||||
<label for="sessions">Number of Sessions:</label>
|
<label for="sessions">Number of Sessions:</label>
|
||||||
<input type="number" id="sessions" placeholder="Number of sessions" value="4" />
|
<input type="number" id="sessions" placeholder="Number of sessions" value="4" />
|
||||||
|
<br />
|
||||||
|
<button id="saveButton">Save Settings</button>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="timer">Connting to server...</div>
|
<div id="timer">Connting to server...</div>
|
||||||
|
|
||||||
|
@ -65,7 +76,7 @@
|
||||||
var data = JSON.parse(event.data);
|
var data = JSON.parse(event.data);
|
||||||
var mode = data.mode;
|
var mode = data.mode;
|
||||||
var session = data.session;
|
var session = data.session;
|
||||||
var totalSession = data.total_sessions;
|
var totalSession = data.settings.sessions;
|
||||||
var timeLeft = data.time_left;
|
var timeLeft = data.time_left;
|
||||||
|
|
||||||
document.getElementById("timer").innerText =
|
document.getElementById("timer").innerText =
|
||||||
|
@ -83,8 +94,8 @@
|
||||||
return minutes.toString().padStart(2, '0') + ":" + remainingSeconds.toString().padStart(2, '0');
|
return minutes.toString().padStart(2, '0') + ":" + remainingSeconds.toString().padStart(2, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Button Click Event
|
// saveButton Click Event
|
||||||
document.getElementById("startButton").addEventListener("click", function () {
|
document.getElementById("saveButton").addEventListener("click", function () {
|
||||||
// Get the values from the input fields
|
// Get the values from the input fields
|
||||||
var password = document.getElementById("password").value;
|
var password = document.getElementById("password").value;
|
||||||
var work = parseInt(document.getElementById("workDuration").value);
|
var work = parseInt(document.getElementById("workDuration").value);
|
||||||
|
@ -94,15 +105,22 @@
|
||||||
|
|
||||||
// Send the start command with the custom config and password
|
// Send the start command with the custom config and password
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
command: "start",
|
command: "updateSettings",
|
||||||
password: password,
|
password: password,
|
||||||
config: {
|
settings: {
|
||||||
work: work,
|
work: work,
|
||||||
shortBreak: shortBreak,
|
shortBreak: shortBreak,
|
||||||
longBreak: longBreak,
|
longBreak: longBreak,
|
||||||
sessions: sessions
|
sessions: sessions
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start Button Click Event
|
||||||
|
document.getElementById("startButton").addEventListener("click", function () {
|
||||||
|
var password = document.getElementById("password").value;
|
||||||
|
// Send the start command with the custom config and password
|
||||||
|
ws.send(JSON.stringify({command: "start", password: password}));
|
||||||
|
|
||||||
// Hide start button and show pause/resume and reset buttons
|
// Hide start button and show pause/resume and reset buttons
|
||||||
document.getElementById("startButton").style.display = "none";
|
document.getElementById("startButton").style.display = "none";
|
||||||
|
|
|
@ -2,7 +2,7 @@ package pomodoro
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
|
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
|
||||||
"git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
// "git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,34 +13,38 @@ var pomodoroResumeChannel = make(chan bool, 1)
|
||||||
var mu sync.Mutex // to synchronize access to shared state
|
var mu sync.Mutex // to synchronize access to shared state
|
||||||
|
|
||||||
// RunPomodoro iterates the Pomodoro work/break sessions.
|
// RunPomodoro iterates the Pomodoro work/break sessions.
|
||||||
func RunPomodoro(config models.GoTomatoPomodoroConfig) {
|
func RunPomodoro() {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
shared.Message.Ongoing = true
|
shared.Message.Ongoing = true
|
||||||
shared.Message.Paused = false
|
shared.Message.Paused = false
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
|
|
||||||
shared.Message.TotalSession = config.Sessions
|
pomodoroConfig := shared.Message.PomodoroSettings
|
||||||
|
|
||||||
for session := 1; session <= config.Sessions; session++ {
|
for session := 1; session <= pomodoroConfig.Sessions; session++ {
|
||||||
shared.Message.Session = session
|
shared.Message.Session = session
|
||||||
shared.Message.Mode = "Work"
|
shared.Message.Mode = "Work"
|
||||||
if !startTimer(config.Work) {
|
if !startTimer(pomodoroConfig.Work) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if session == config.Sessions {
|
if session == pomodoroConfig.Sessions {
|
||||||
shared.Message.Mode = "LongBreak"
|
shared.Message.Mode = "LongBreak"
|
||||||
if !startTimer(config.LongBreak) {
|
if !startTimer(pomodoroConfig.LongBreak) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shared.Message.Mode = "ShortBreak"
|
shared.Message.Mode = "ShortBreak"
|
||||||
if !startTimer(config.ShortBreak) {
|
if !startTimer(pomodoroConfig.ShortBreak) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
shared.Message.Mode = "End"
|
||||||
}
|
}
|
||||||
|
|
||||||
shared.Message = shared.ResetToDefault()
|
mu.Lock()
|
||||||
|
shared.Message.Ongoing = false
|
||||||
|
shared.Message.Paused = false
|
||||||
|
mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPomodoro resets the running Pomodoro timer.
|
// ResetPomodoro resets the running Pomodoro timer.
|
||||||
|
|
|
@ -8,10 +8,10 @@ var Message = ResetToDefault()
|
||||||
|
|
||||||
func ResetToDefault() models.ServerMessage {
|
func ResetToDefault() models.ServerMessage {
|
||||||
return models.ServerMessage{
|
return models.ServerMessage{
|
||||||
Mode: "",
|
Mode: "Idle",
|
||||||
|
PomodoroSettings: DefaultPomodoroConfig,
|
||||||
Session: 0,
|
Session: 0,
|
||||||
TotalSession: 0,
|
TimeLeft: DefaultPomodoroConfig.Work,
|
||||||
TimeLeft: 0,
|
|
||||||
Ongoing: false,
|
Ongoing: false,
|
||||||
Paused: false,
|
Paused: false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ import (
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pomodoroConfig = shared.DefaultPomodoroConfig
|
|
||||||
|
|
||||||
// handleClientCommands listens for commands from WebSocket clients
|
// handleClientCommands listens for commands from WebSocket clients
|
||||||
func handleClientCommands(ws *websocket.Conn) {
|
func handleClientCommands(ws *websocket.Conn) {
|
||||||
for {
|
for {
|
||||||
|
@ -35,10 +33,7 @@ func handleClientCommands(ws *websocket.Conn) {
|
||||||
switch clientCommand.Command {
|
switch clientCommand.Command {
|
||||||
case "start":
|
case "start":
|
||||||
if !pomodoro.IsPomodoroOngoing() {
|
if !pomodoro.IsPomodoroOngoing() {
|
||||||
if clientCommand.Config != shared.UnsetPomodoroConfig {
|
go pomodoro.RunPomodoro() // Start the timer with the list of clients
|
||||||
pomodoroConfig = clientCommand.Config
|
|
||||||
}
|
|
||||||
go pomodoro.RunPomodoro(pomodoroConfig) // Start the timer with the list of clients
|
|
||||||
}
|
}
|
||||||
case "stop":
|
case "stop":
|
||||||
if pomodoro.IsPomodoroOngoing() {
|
if pomodoro.IsPomodoroOngoing() {
|
||||||
|
@ -52,6 +47,14 @@ func handleClientCommands(ws *websocket.Conn) {
|
||||||
if pomodoro.IsPomodoroOngoing() && pomodoro.IsPomodoroPaused() {
|
if pomodoro.IsPomodoroOngoing() && pomodoro.IsPomodoroPaused() {
|
||||||
pomodoro.ResumePomodoro() // Resume the timer
|
pomodoro.ResumePomodoro() // Resume the timer
|
||||||
}
|
}
|
||||||
|
case "updateSettings":
|
||||||
|
if !pomodoro.IsPomodoroOngoing() {
|
||||||
|
if clientCommand.PomodoroSettings != shared.UnsetPomodoroConfig {
|
||||||
|
shared.Message.PomodoroSettings = clientCommand.PomodoroSettings
|
||||||
|
shared.Message.TimeLeft = clientCommand.PomodoroSettings.Work
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
type ClientCommand struct {
|
type ClientCommand struct {
|
||||||
Command string `json:"command"` // comman send to the server
|
Command string `json:"command"` // comman send to the server
|
||||||
Password string `json:"password"` // pomodoro control password
|
Password string `json:"password"` // pomodoro control password
|
||||||
Config GoTomatoPomodoroConfig `json:"config"` // pomodoro config
|
PomodoroSettings GoTomatoPomodoroConfig `json:"settings"` // pomodoro config
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
|
|
@ -2,9 +2,9 @@ package models
|
||||||
|
|
||||||
// ServerMessage represents the data sent to the client via WebSocket.
|
// ServerMessage represents the data sent to the client via WebSocket.
|
||||||
type ServerMessage struct {
|
type ServerMessage struct {
|
||||||
Mode string `json:"mode"` // "Work", "ShortBreak", or "LongBreak"
|
Mode string `json:"mode"` // "Idle", "Work", "ShortBreak", "LongBreak" or "End"
|
||||||
|
PomodoroSettings GoTomatoPomodoroConfig `json:"settings"` // The currrent pomodoro settings
|
||||||
Session int `json:"session"` // Current session number
|
Session int `json:"session"` // Current session number
|
||||||
TotalSession int `json:"total_sessions"` // Total number of sessions
|
|
||||||
TimeLeft int `json:"time_left"` // Remaining time in seconds
|
TimeLeft int `json:"time_left"` // Remaining time in seconds
|
||||||
Ongoing bool `json:"ongoing"` // Ongoing pomodoro
|
Ongoing bool `json:"ongoing"` // Ongoing pomodoro
|
||||||
Paused bool `json:"paused"` // Is timer paused
|
Paused bool `json:"paused"` // Is timer paused
|
||||||
|
|
Loading…
Reference in a new issue