Skip to content

Commit

Permalink
Merge pull request #27 from dorianim/feat/start-on-demand
Browse files Browse the repository at this point in the history
Feat: fully support start on demand
  • Loading branch information
dorianim committed Jul 4, 2023
2 parents e5121b3 + f7dc654 commit e4f68b1
Show file tree
Hide file tree
Showing 23 changed files with 408 additions and 131 deletions.
6 changes: 5 additions & 1 deletion display/include/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ struct TimerSegment {
char label[32];
};

enum class PreStartBehaviour { SHOW_ZERO, RUN_NORMALLY };
enum class PreStartBehaviour {
SHOW_FIRST_SEGMENT,
SHOW_LAST_SEGMENT,
RUN_NORMALLY
};

struct DisplayOptions {
PreStartBehaviour pre_start_behaviour;
Expand Down
7 changes: 5 additions & 2 deletions display/src/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,15 @@ uint32_t _parseHexColor(const char *c) {

void _loadDisplayOptions(JsonObject &data) {
String pre_start_behaviour = data["pre_start_behaviour"];
if (pre_start_behaviour == "ShowZero") {
if (pre_start_behaviour == "ShowLastSegment") {
_timerData->display_options.pre_start_behaviour =
timer::PreStartBehaviour::SHOW_ZERO;
timer::PreStartBehaviour::SHOW_LAST_SEGMENT;
} else if (pre_start_behaviour == "RunNormally") {
_timerData->display_options.pre_start_behaviour =
timer::PreStartBehaviour::RUN_NORMALLY;
} else {
_timerData->display_options.pre_start_behaviour =
timer::PreStartBehaviour::SHOW_FIRST_SEGMENT;
}

_timerData->display_options.clock = data["clock"];
Expand Down
35 changes: 23 additions & 12 deletions display/src/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@ TimerData _timerData;

TimerData *timerData() { return &_timerData; }

ActiveSegment calculateCurrentSegment(TIME timeOffset) {
if (!_timerData.valid || timeOffset == 0) {
return {0, 0xfff, "", 0};
TIME calculateTimeInCurrentRound(TIME currentTime) {

if (currentTime < _timerData.start_at &&
_timerData.display_options.pre_start_behaviour ==
PreStartBehaviour::SHOW_FIRST_SEGMENT) {
return 1;
}

long totalTimePerRound = 0;
for (int i = 0; i < 10 && _timerData.segments[i].valid; i++) {
totalTimePerRound += _timerData.segments[i].time;
}

TIME currentTime = (TIME)millis() + timeOffset;
if (currentTime < _timerData.start_at &&
_timerData.display_options.pre_start_behaviour ==
PreStartBehaviour::SHOW_ZERO) {
return {0, 0xfff, "", currentTime};
PreStartBehaviour::SHOW_LAST_SEGMENT) {
return totalTimePerRound;
}

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

long totalTimePerRound = 0;
for (int i = 0; i < 10 && _timerData.segments[i].valid; i++) {
totalTimePerRound += _timerData.segments[i].time;
if (!_timerData.repeat && elapsedTime > totalTimePerRound) {
return totalTimePerRound;
}

if (!_timerData.repeat && elapsedTime > totalTimePerRound) {
return {0, 0xfff, "", currentTime};
return elapsedTime % totalTimePerRound;
}

ActiveSegment calculateCurrentSegment(TIME timeOffset) {
if (!_timerData.valid || timeOffset == 0) {
return {0, 0xfff, "", 0};
}

long timeInCurrentRound = elapsedTime % totalTimePerRound;
TIME currentTime = (TIME)millis() + timeOffset;
long timeInCurrentRound = calculateTimeInCurrentRound(currentTime);

int currentSegmentIndex = 0;
long timeInCurrentSegment = 0;
Expand Down
1 change: 1 addition & 0 deletions src/redis_migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod display_options;
mod pre_start_behaviour;
mod segment;
mod sound;
mod tests;
mod timer;
mod timer_metadata;
Expand Down
50 changes: 48 additions & 2 deletions src/redis_migrations/segment.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use serde::Deserialize;

use crate::{color::Color, repository::Segment};
use crate::{
color::Color,
repository::{Segment, Sound},
};

use super::sound::RedisSound;

#[derive(Deserialize, Clone)]
#[serde(untagged)]
pub enum RedisSegment {
V1(SegmentV1),
V0(SegmentV0),
}

impl Into<Segment> for RedisSegment {
fn into(self) -> Segment {
match self {
RedisSegment::V0(v0) => v0.into(),
RedisSegment::V1(v1) => v1.into(),
}
}
}
Expand All @@ -20,6 +27,32 @@ fn default_zero() -> u32 {
0
}

/// === V1 ===

#[derive(Deserialize, Clone)]
pub struct SegmentV1 {
label: String,
time: u32,
color: Option<Color>,
#[serde(default = "default_zero")]
count_to: u32,
sounds: Vec<RedisSound>,
}

impl Into<Segment> for SegmentV1 {
fn into(self) -> Segment {
Segment {
label: self.label,
time: self.time,
color: self.color,
count_to: self.count_to,
sounds: self.sounds.into_iter().map(|s| s.into()).collect(),
}
}
}

/// === V0 ===

#[derive(Deserialize, Clone)]
pub struct SegmentV0 {
label: String,
Expand All @@ -32,12 +65,25 @@ pub struct SegmentV0 {

impl Into<Segment> for SegmentV0 {
fn into(self) -> Segment {
let mut sounds: Vec<Sound> = Vec::new();

if self.sound {
sounds.push(Sound {
filename: "beep.mp3".to_string(),
trigger_time: 60,
});
sounds.push(Sound {
filename: "countdown.mp3".to_string(),
trigger_time: 5,
});
}

Segment {
label: self.label,
time: self.time,
sound: self.sound,
color: self.color,
count_to: self.count_to,
sounds: sounds,
}
}
}
32 changes: 32 additions & 0 deletions src/redis_migrations/sound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use serde::Deserialize;

use crate::repository::Sound;

#[derive(Deserialize, Clone)]
#[serde(untagged)]
pub enum RedisSound {
V0(SoundV0),
}

impl Into<Sound> for RedisSound {
fn into(self) -> Sound {
match self {
RedisSound::V0(v0) => v0.into(),
}
}
}

#[derive(Deserialize, Clone)]
pub struct SoundV0 {
pub filename: String,
pub trigger_time: u32,
}

impl Into<Sound> for SoundV0 {
fn into(self) -> Sound {
Sound {
filename: self.filename,
trigger_time: self.trigger_time,
}
}
}
17 changes: 15 additions & 2 deletions src/redis_migrations/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ fn test_v0() {
let timer: Timer = timer.into();
assert_eq!(timer.segments.len(), 1);
assert_eq!(timer.segments[0].label, "Boulder");
assert_eq!(timer.segments[0].sounds.len(), 2);
assert_eq!(timer.segments[0].sounds[0].filename, "beep.mp3");
assert_eq!(timer.segments[0].sounds[0].trigger_time, 60);
assert_eq!(timer.segments[0].sounds[1].filename, "countdown.mp3");
assert_eq!(timer.segments[0].sounds[1].trigger_time, 5);
assert_eq!(timer.metadata.delay_start_stop, 0);
assert_eq!(
timer.display_options.pre_start_behaviour,
Expand All @@ -47,9 +52,14 @@ fn test_v1() {
{
"label":"Boulder",
"time":230000,
"sound":true,
"color":"#26A269",
"count_to":11000
"count_to":11000,
"sounds": [
{
"filename": "beep.mp3",
"trigger_time": 60
}
]
}
],
"id":"v0",
Expand All @@ -71,6 +81,9 @@ fn test_v1() {
let timer: Timer = timer.into();
assert_eq!(timer.segments.len(), 1);
assert_eq!(timer.segments[0].label, "Boulder");
assert_eq!(timer.segments[0].sounds.len(), 1);
assert_eq!(timer.segments[0].sounds[0].filename, "beep.mp3");
assert_eq!(timer.segments[0].sounds[0].trigger_time, 60);
assert_eq!(timer.metadata.delay_start_stop, 5);
assert_eq!(
timer.display_options.pre_start_behaviour,
Expand Down
4 changes: 2 additions & 2 deletions src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ use tokio::{
pub struct Segment {
pub label: String,
pub time: u32,
pub sound: bool,
pub color: Option<Color>,
pub count_to: u32,
pub sounds: Vec<Sound>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Sound {
pub filename: String,
pub play_at: u32,
pub trigger_time: u32,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
Expand Down
5 changes: 4 additions & 1 deletion web/src/components/HelpPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import Fa from 'svelte-fa';
import newUniqueId from 'locally-unique-id-generator';
let clazz = '';
export { clazz as class };
const id = newUniqueId();
</script>

<span>
<span class={clazz}>
<div
class="w-fit"
use:popup={{
Expand Down
13 changes: 2 additions & 11 deletions web/src/routes/manage/[id]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
<script lang="ts">
import Fa from 'svelte-fa';
import type { PageData } from './$types';
import {
faChevronRight,
faCircleCheck,
faClose,
faEdit,
faForward,
faPause,
faPlay,
faRefresh
} from '@fortawesome/free-solid-svg-icons';
import { faEdit, faForward, faPause, faPlay, faRefresh } from '@fortawesome/free-solid-svg-icons';
import {
updateTimer,
calculateStartTimeAfterResume,
Expand Down Expand Up @@ -41,7 +32,7 @@
};
const restartTimer = () => {
_updateTimer(new Date().getTime());
_updateTimer(new Date().getTime() + timerData.metadata.delay_start_stop);
};
const stopTimer = () => {
Expand Down
4 changes: 1 addition & 3 deletions web/src/routes/manage/[id]/edit/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script lang="ts">
import { ProgressRadial, SlideToggle } from '@skeletonlabs/skeleton';
import { get } from 'svelte/store';
import { API_URL } from 'stores';
import { ProgressRadial } from '@skeletonlabs/skeleton';
import type { Timer, TimerUpdateRequest } from 'types/timer';
import type { PageData } from '../$types';
import TimerForm from './TimerForm.svelte';
Expand Down
29 changes: 25 additions & 4 deletions web/src/routes/manage/[id]/edit/SegmentForm.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
<script lang="ts">
import { faRemove } from '@fortawesome/free-solid-svg-icons';
import { SlideToggle } from '@skeletonlabs/skeleton';
import Fa from 'svelte-fa';
import type { Segment } from 'types/segment';
import TimeInputField from './TimeInputField.svelte';
import { detectSoundPreset, soundPresets } from 'utils/sounds';
export let segment: Segment;
let clazz: string = '';
export { clazz as class };
let soundPreset = detectSoundPreset(segment.sounds);
const updateSegmentSounds = (preset: string | null) => {
if (!preset) {
segment.sounds = [];
return;
}
segment.sounds = soundPresets[preset];
};
$: updateSegmentSounds(soundPreset);
</script>

<div class="p-[2px] {clazz}">
Expand All @@ -32,9 +44,18 @@
<TimeInputField class="flex-1" bind:time={segment.count_to} label="Count to:" />
</div>

<SlideToggle active="bg-primary-500" name="sound" size="sm" bind:checked={segment.sound}
>enable sound</SlideToggle
>
<label class="">
Sounds to play:
<select class="select" bind:value={soundPreset}>
<option value={null}>No sounds</option>
<option value="beepOneMinute_countdownFiveSeconds"
>Beep at one minute and countdown at five seconds</option
>
<option value="beepFourMinutesOneMinute_countdownFiveSeconds"
>Beep at four minutes and one minute and countdown at five seconds</option
>
</select>
</label>

<label class="label">
<div class="flex items-center">
Expand Down
Loading

0 comments on commit e4f68b1

Please sign in to comment.