Skip to content

Commit e4f68b1

Browse files
authored
Merge pull request #27 from dorianim/feat/start-on-demand
Feat: fully support start on demand
2 parents e5121b3 + f7dc654 commit e4f68b1

File tree

23 files changed

+408
-131
lines changed

23 files changed

+408
-131
lines changed

display/include/timer.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ struct TimerSegment {
1414
char label[32];
1515
};
1616

17-
enum class PreStartBehaviour { SHOW_ZERO, RUN_NORMALLY };
17+
enum class PreStartBehaviour {
18+
SHOW_FIRST_SEGMENT,
19+
SHOW_LAST_SEGMENT,
20+
RUN_NORMALLY
21+
};
1822

1923
struct DisplayOptions {
2024
PreStartBehaviour pre_start_behaviour;

display/src/socket.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,15 @@ uint32_t _parseHexColor(const char *c) {
109109

110110
void _loadDisplayOptions(JsonObject &data) {
111111
String pre_start_behaviour = data["pre_start_behaviour"];
112-
if (pre_start_behaviour == "ShowZero") {
112+
if (pre_start_behaviour == "ShowLastSegment") {
113113
_timerData->display_options.pre_start_behaviour =
114-
timer::PreStartBehaviour::SHOW_ZERO;
114+
timer::PreStartBehaviour::SHOW_LAST_SEGMENT;
115115
} else if (pre_start_behaviour == "RunNormally") {
116116
_timerData->display_options.pre_start_behaviour =
117117
timer::PreStartBehaviour::RUN_NORMALLY;
118+
} else {
119+
_timerData->display_options.pre_start_behaviour =
120+
timer::PreStartBehaviour::SHOW_FIRST_SEGMENT;
118121
}
119122

120123
_timerData->display_options.clock = data["clock"];

display/src/timer.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,23 @@ TimerData _timerData;
88

99
TimerData *timerData() { return &_timerData; }
1010

11-
ActiveSegment calculateCurrentSegment(TIME timeOffset) {
12-
if (!_timerData.valid || timeOffset == 0) {
13-
return {0, 0xfff, "", 0};
11+
TIME calculateTimeInCurrentRound(TIME currentTime) {
12+
13+
if (currentTime < _timerData.start_at &&
14+
_timerData.display_options.pre_start_behaviour ==
15+
PreStartBehaviour::SHOW_FIRST_SEGMENT) {
16+
return 1;
17+
}
18+
19+
long totalTimePerRound = 0;
20+
for (int i = 0; i < 10 && _timerData.segments[i].valid; i++) {
21+
totalTimePerRound += _timerData.segments[i].time;
1422
}
1523

16-
TIME currentTime = (TIME)millis() + timeOffset;
1724
if (currentTime < _timerData.start_at &&
1825
_timerData.display_options.pre_start_behaviour ==
19-
PreStartBehaviour::SHOW_ZERO) {
20-
return {0, 0xfff, "", currentTime};
26+
PreStartBehaviour::SHOW_LAST_SEGMENT) {
27+
return totalTimePerRound;
2128
}
2229

2330
long elapsedTime = currentTime - _timerData.start_at;
@@ -26,16 +33,20 @@ ActiveSegment calculateCurrentSegment(TIME timeOffset) {
2633
elapsedTime = _timerData.stop_at - _timerData.start_at;
2734
}
2835

29-
long totalTimePerRound = 0;
30-
for (int i = 0; i < 10 && _timerData.segments[i].valid; i++) {
31-
totalTimePerRound += _timerData.segments[i].time;
36+
if (!_timerData.repeat && elapsedTime > totalTimePerRound) {
37+
return totalTimePerRound;
3238
}
3339

34-
if (!_timerData.repeat && elapsedTime > totalTimePerRound) {
35-
return {0, 0xfff, "", currentTime};
40+
return elapsedTime % totalTimePerRound;
41+
}
42+
43+
ActiveSegment calculateCurrentSegment(TIME timeOffset) {
44+
if (!_timerData.valid || timeOffset == 0) {
45+
return {0, 0xfff, "", 0};
3646
}
3747

38-
long timeInCurrentRound = elapsedTime % totalTimePerRound;
48+
TIME currentTime = (TIME)millis() + timeOffset;
49+
long timeInCurrentRound = calculateTimeInCurrentRound(currentTime);
3950

4051
int currentSegmentIndex = 0;
4152
long timeInCurrentSegment = 0;

src/redis_migrations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod display_options;
22
mod pre_start_behaviour;
33
mod segment;
4+
mod sound;
45
mod tests;
56
mod timer;
67
mod timer_metadata;

src/redis_migrations/segment.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
use serde::Deserialize;
22

3-
use crate::{color::Color, repository::Segment};
3+
use crate::{
4+
color::Color,
5+
repository::{Segment, Sound},
6+
};
7+
8+
use super::sound::RedisSound;
49

510
#[derive(Deserialize, Clone)]
611
#[serde(untagged)]
712
pub enum RedisSegment {
13+
V1(SegmentV1),
814
V0(SegmentV0),
915
}
1016

1117
impl Into<Segment> for RedisSegment {
1218
fn into(self) -> Segment {
1319
match self {
1420
RedisSegment::V0(v0) => v0.into(),
21+
RedisSegment::V1(v1) => v1.into(),
1522
}
1623
}
1724
}
@@ -20,6 +27,32 @@ fn default_zero() -> u32 {
2027
0
2128
}
2229

30+
/// === V1 ===
31+
32+
#[derive(Deserialize, Clone)]
33+
pub struct SegmentV1 {
34+
label: String,
35+
time: u32,
36+
color: Option<Color>,
37+
#[serde(default = "default_zero")]
38+
count_to: u32,
39+
sounds: Vec<RedisSound>,
40+
}
41+
42+
impl Into<Segment> for SegmentV1 {
43+
fn into(self) -> Segment {
44+
Segment {
45+
label: self.label,
46+
time: self.time,
47+
color: self.color,
48+
count_to: self.count_to,
49+
sounds: self.sounds.into_iter().map(|s| s.into()).collect(),
50+
}
51+
}
52+
}
53+
54+
/// === V0 ===
55+
2356
#[derive(Deserialize, Clone)]
2457
pub struct SegmentV0 {
2558
label: String,
@@ -32,12 +65,25 @@ pub struct SegmentV0 {
3265

3366
impl Into<Segment> for SegmentV0 {
3467
fn into(self) -> Segment {
68+
let mut sounds: Vec<Sound> = Vec::new();
69+
70+
if self.sound {
71+
sounds.push(Sound {
72+
filename: "beep.mp3".to_string(),
73+
trigger_time: 60,
74+
});
75+
sounds.push(Sound {
76+
filename: "countdown.mp3".to_string(),
77+
trigger_time: 5,
78+
});
79+
}
80+
3581
Segment {
3682
label: self.label,
3783
time: self.time,
38-
sound: self.sound,
3984
color: self.color,
4085
count_to: self.count_to,
86+
sounds: sounds,
4187
}
4288
}
4389
}

src/redis_migrations/sound.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use serde::Deserialize;
2+
3+
use crate::repository::Sound;
4+
5+
#[derive(Deserialize, Clone)]
6+
#[serde(untagged)]
7+
pub enum RedisSound {
8+
V0(SoundV0),
9+
}
10+
11+
impl Into<Sound> for RedisSound {
12+
fn into(self) -> Sound {
13+
match self {
14+
RedisSound::V0(v0) => v0.into(),
15+
}
16+
}
17+
}
18+
19+
#[derive(Deserialize, Clone)]
20+
pub struct SoundV0 {
21+
pub filename: String,
22+
pub trigger_time: u32,
23+
}
24+
25+
impl Into<Sound> for SoundV0 {
26+
fn into(self) -> Sound {
27+
Sound {
28+
filename: self.filename,
29+
trigger_time: self.trigger_time,
30+
}
31+
}
32+
}

src/redis_migrations/tests.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ fn test_v0() {
3232
let timer: Timer = timer.into();
3333
assert_eq!(timer.segments.len(), 1);
3434
assert_eq!(timer.segments[0].label, "Boulder");
35+
assert_eq!(timer.segments[0].sounds.len(), 2);
36+
assert_eq!(timer.segments[0].sounds[0].filename, "beep.mp3");
37+
assert_eq!(timer.segments[0].sounds[0].trigger_time, 60);
38+
assert_eq!(timer.segments[0].sounds[1].filename, "countdown.mp3");
39+
assert_eq!(timer.segments[0].sounds[1].trigger_time, 5);
3540
assert_eq!(timer.metadata.delay_start_stop, 0);
3641
assert_eq!(
3742
timer.display_options.pre_start_behaviour,
@@ -47,9 +52,14 @@ fn test_v1() {
4752
{
4853
"label":"Boulder",
4954
"time":230000,
50-
"sound":true,
5155
"color":"#26A269",
52-
"count_to":11000
56+
"count_to":11000,
57+
"sounds": [
58+
{
59+
"filename": "beep.mp3",
60+
"trigger_time": 60
61+
}
62+
]
5363
}
5464
],
5565
"id":"v0",
@@ -71,6 +81,9 @@ fn test_v1() {
7181
let timer: Timer = timer.into();
7282
assert_eq!(timer.segments.len(), 1);
7383
assert_eq!(timer.segments[0].label, "Boulder");
84+
assert_eq!(timer.segments[0].sounds.len(), 1);
85+
assert_eq!(timer.segments[0].sounds[0].filename, "beep.mp3");
86+
assert_eq!(timer.segments[0].sounds[0].trigger_time, 60);
7487
assert_eq!(timer.metadata.delay_start_stop, 5);
7588
assert_eq!(
7689
timer.display_options.pre_start_behaviour,

src/repository.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ use tokio::{
1414
pub struct Segment {
1515
pub label: String,
1616
pub time: u32,
17-
pub sound: bool,
1817
pub color: Option<Color>,
1918
pub count_to: u32,
19+
pub sounds: Vec<Sound>,
2020
}
2121

2222
#[derive(Serialize, Deserialize, Clone, Debug)]
2323
pub struct Sound {
2424
pub filename: String,
25-
pub play_at: u32,
25+
pub trigger_time: u32,
2626
}
2727

2828
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]

web/src/components/HelpPopup.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import Fa from 'svelte-fa';
55
import newUniqueId from 'locally-unique-id-generator';
66
7+
let clazz = '';
8+
export { clazz as class };
9+
710
const id = newUniqueId();
811
</script>
912

10-
<span>
13+
<span class={clazz}>
1114
<div
1215
class="w-fit"
1316
use:popup={{

web/src/routes/manage/[id]/+page.svelte

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
11
<script lang="ts">
22
import Fa from 'svelte-fa';
33
import type { PageData } from './$types';
4-
import {
5-
faChevronRight,
6-
faCircleCheck,
7-
faClose,
8-
faEdit,
9-
faForward,
10-
faPause,
11-
faPlay,
12-
faRefresh
13-
} from '@fortawesome/free-solid-svg-icons';
4+
import { faEdit, faForward, faPause, faPlay, faRefresh } from '@fortawesome/free-solid-svg-icons';
145
import {
156
updateTimer,
167
calculateStartTimeAfterResume,
@@ -41,7 +32,7 @@
4132
};
4233
4334
const restartTimer = () => {
44-
_updateTimer(new Date().getTime());
35+
_updateTimer(new Date().getTime() + timerData.metadata.delay_start_stop);
4536
};
4637
4738
const stopTimer = () => {

0 commit comments

Comments
 (0)