Skip to content
This repository was archived by the owner on Nov 7, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ graphics_draw_text(ctx, text,
GTextAlignmentLeft, NULL);
}

void timer_draw_row(Timer* timer, GContext* ctx) {
void timer_draw_row(Timer* timer, TimerTimestamp timestamp, GContext* ctx) {
char* time_left = malloc(12);
timer_time_str(timer->current_time, settings()->timers_hours, time_left, 12);
timer_display_str(timer, timestamp, settings()->timers_hours, time_left, 12);

graphics_context_set_text_color(ctx, GColorBlack);
graphics_context_set_fill_color(ctx, GColorBlack);
Expand Down Expand Up @@ -95,7 +95,7 @@ void timer_draw_row(Timer* timer, GContext* ctx) {
}

if (timer->type == TIMER_TYPE_TIMER) {
uint8_t width = (144 * timer->current_time) / timer->length;
uint8_t width = (144 * timer_get_display_time(timer, timestamp)) / timer->length;
graphics_fill_rect(ctx, GRect(0, 31, width, 2), 0, GCornerNone);
}

Expand Down
2 changes: 1 addition & 1 deletion src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ src/common.h
#include "timer.h"

void menu_draw_row_icon_text(GContext* ctx, char* text, GBitmap* icon);
void timer_draw_row(Timer* timer, GContext* ctx);
void timer_draw_row(Timer* timer, TimerTimestamp reference, GContext* ctx);
void menu_draw_option(GContext* ctx, char* option, char* value);
void uppercase(char* str);
21 changes: 21 additions & 0 deletions src/migration.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,27 @@ typedef struct {
time_t save_time;
} TimerBlockTiny;

typedef struct TimerV3 {
uint16_t id;
TimerType type;
uint32_t length;
uint32_t current_time;
TimerStatus status;
TimerVibration vibration;
uint8_t repeat;
uint8_t repeat_count;
AppTimer* timer;
WakeupId wakeup_id;
char label[24];
} TimerV3;

typedef struct {
TimerV3 timers[TIMER_BLOCK_SIZE];
uint8_t total_timers;
time_t save_time;
} TimerBlockV3;


// Struct of the original settings.
typedef struct {
bool save_timers_auto; // Automatically save timers on exit and load them when the app restarts?
Expand Down
216 changes: 126 additions & 90 deletions src/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,76 @@ src/timer.c
#include "settings.h"
#include "windows/win-vibrate.h"

static void timer_tick(void* context);
static void timer_finish(Timer* timer);
static void timer_schedule_tick(Timer* timer);
static void timer_cancel_tick(Timer* timer);
static void timer_finish(Timer* timer, TimerTimestamp reference);
static void timer_schedule_wakeup(Timer* timer, uint16_t offset);
static void timer_cancel_wakeup(Timer* timer);
static void timer_set_id(Timer* timer);
static void timer_completed_action(Timer* timer);
static void timer_transition_to_stop(Timer* timer, TimerTimestamp reference_time);
static void timer_transition_to_start(Timer* timer, TimerTimestamp reference_time);
static void timer_transition_to(Timer* timer, TimerTimestamp reference_time, TimerStatus new_status);
static void timer_set_running_time(Timer* timer, TimerTimestamp reference_time, int32_t running_time);
static void timer_add_running_time(Timer* timer, int32_t add_seconds);
static bool timer_has_finished(Timer* timer, TimerTimestamp reference);
static uint32_t timer_display2running_time(Timer* timer, uint32_t display_time);

TimerTimestamp timer_get_end_timestamp(Timer* timer) {
switch (timer->type) {
case TIMER_TYPE_TIMER: return timer->start_timestamp + timer->length - timer->paused_offset;
default: return 0;
}
}

uint32_t timer_get_running_time(Timer* timer, TimerTimestamp reference_time) {
if (TIMER_STATUS_RUNNING == timer->status) {
return reference_time - timer->start_timestamp + timer->paused_offset;
} else {
// Both reference_time and timer->start_timestamp are meaningless.
return timer->paused_offset;
}
}

static void timer_transition_to_stop(Timer* timer, TimerTimestamp reference_time) {
timer->paused_offset += reference_time - timer->start_timestamp;
}

static void timer_transition_to_start(Timer* timer, TimerTimestamp reference_time) {
timer->start_timestamp = reference_time;
}

static void timer_transition_to(Timer* timer, TimerTimestamp reference_time, TimerStatus new_status) {
if (TIMER_STATUS_RUNNING != timer->status && TIMER_STATUS_RUNNING == new_status) {
timer_transition_to_start(timer, reference_time);
} else if (TIMER_STATUS_RUNNING == timer-> status && TIMER_STATUS_RUNNING != new_status) {
timer_transition_to_stop(timer, reference_time);
}
timer->status = new_status;
}

static void timer_set_running_time(Timer* timer, TimerTimestamp reference_time, int32_t running_time) {
timer->start_timestamp = reference_time;
timer->paused_offset = running_time;
}

int32_t timer_get_display_time(Timer* timer, TimerTimestamp reference_time) {
switch (timer->type) {
case TIMER_TYPE_TIMER: return timer->length - timer_get_running_time(timer, reference_time);
case TIMER_TYPE_STOPWATCH: return timer_get_running_time(timer, reference_time);
default: return 0;
}
}

static uint32_t timer_display2running_time(Timer* timer, uint32_t display_time) {
switch (timer->type) {
case TIMER_TYPE_TIMER: return timer->length - display_time;
case TIMER_TYPE_STOPWATCH: return display_time;
default: return 0;
}
}

static void timer_add_running_time(Timer* timer, int32_t add_seconds) {
timer->paused_offset += add_seconds;
}

void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len) {
int hours = timer_time / 3600;
Expand All @@ -57,71 +119,63 @@ void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len)
}
}

void timer_start(Timer* timer) {
switch (timer->type) {
case TIMER_TYPE_TIMER:
timer->current_time = timer->length;
break;
case TIMER_TYPE_STOPWATCH:
timer->current_time = 0;
break;
}
timer->status = TIMER_STATUS_RUNNING;
timer_schedule_tick(timer);
timer_schedule_wakeup(timer, 0);
timers_mark_updated();
void timer_display_str(Timer* timer, TimerTimestamp reference, bool showHours, char* str, int str_len) {
int32_t current_time = timer_get_display_time(timer, reference);
return timer_time_str(current_time, showHours, str, str_len);
}

void timer_start(Timer* timer, TimerTimestamp reference) {
timer_reset(timer);
timer_resume(timer, reference);
}

void timer_pause(Timer* timer) {
timer->status = TIMER_STATUS_PAUSED;
timer_cancel_tick(timer);
void timer_pause(Timer* timer, TimerTimestamp reference) {
timer_transition_to(timer, reference, TIMER_STATUS_PAUSED);
timer_cancel_wakeup(timer);
timers_mark_updated();
}

void timer_resume(Timer* timer) {
timer->status = TIMER_STATUS_RUNNING;
timer_schedule_tick(timer);
void timer_resume(Timer* timer, TimerTimestamp reference) {
timer_transition_to(timer, reference, TIMER_STATUS_RUNNING);
timer_schedule_wakeup(timer, 0);
timers_mark_updated();
}

void timer_reset(Timer* timer) {
timer_pause(timer);
switch (timer->type) {
case TIMER_TYPE_TIMER:
timer->current_time = timer->length;
break;
case TIMER_TYPE_STOPWATCH:
timer->current_time = 0;
break;
}
timer->status = TIMER_STATUS_STOPPED;
// Magic starts
timer_transition_to(timer, 0, TIMER_STATUS_STOPPED);
timer_set_running_time(timer, 0, 0);
// The next timer_transition_to(timer, reference, TIMER_STATUS_RUNNING)
// call on this timer will work correctly. This is because the reference
// time doesn't matter on a stop -> start transition.
// Magic ends
timer_cancel_wakeup(timer);
timers_mark_updated();
}

void timer_restart(Timer* timer, TimerTimestamp reference) {
timer_transition_to(timer, reference, TIMER_STATUS_RUNNING);
uint32_t running_time = timer_get_running_time(timer, reference);
timer_set_running_time(timer, reference, running_time % timer->length);
timer_schedule_wakeup(timer, 0);
timers_mark_updated();
}

void timer_restore(Timer* timer, uint16_t seconds_elapsed) {
timer->timer = NULL;
void timer_restore(Timer* timer, TimerTimestamp reference) {
timer_tick(timer, reference);

if (timer->status == TIMER_STATUS_RUNNING) {
switch (timer->type) {
case TIMER_TYPE_STOPWATCH:
timer->current_time += seconds_elapsed;
break;
case TIMER_TYPE_TIMER: {
if (seconds_elapsed >= timer->current_time) {
timer->current_time = 0;
timer->status = TIMER_STATUS_DONE;
}
else {
timer->current_time -= seconds_elapsed;
}
break;
}
}
timer_resume(timer, reference);
}
if (timer->status == TIMER_STATUS_RUNNING) {
timer_resume(timer);
}

void timer_restore_legacy(Timer* timer, TimerTimestamp reference, uint32_t offset, uint32_t display_time) {
uint32_t running_time = timer_display2running_time(timer, display_time);
timer_set_running_time(timer, reference, running_time);
if (TIMER_STATUS_RUNNING == timer->status) {
timer_add_running_time(timer, offset);
}
timer_restore(timer, reference);
}

Timer* timer_clone(Timer* timer) {
Expand Down Expand Up @@ -153,8 +207,8 @@ Timer* timer_create_timer(void) {
timer->type = TIMER_TYPE_TIMER;
timer->vibration = settings()->timers_vibration;
timer->length = settings()->timers_duration;
timer->paused_offset = 0;
timer->wakeup_id = -1;
timer->timer = NULL;
timer->repeat = 0;
timer->label[0] = 0;
timer->status = TIMER_STATUS_STOPPED;
Expand All @@ -165,51 +219,37 @@ Timer* timer_create_timer(void) {
Timer* timer_create_stopwatch(void) {
Timer* stopwatch = malloc(sizeof(Timer));
stopwatch->type = TIMER_TYPE_STOPWATCH;
stopwatch->length = stopwatch->current_time = 0;
stopwatch->length = 0;
stopwatch->paused_offset = 0;
stopwatch->label[0] = 0;
stopwatch->status = TIMER_STATUS_STOPPED;
timer_set_id(stopwatch);
return stopwatch;
}

static void timer_tick(void* context) {
Timer* timer = (Timer*)context;
timer->timer = NULL;
switch (timer->type) {
case TIMER_TYPE_STOPWATCH:
timer->current_time += 1;
break;
case TIMER_TYPE_TIMER:
timer->current_time -= 1;
if (timer->current_time <= 0) {
timer_finish(timer);
}
break;
void timer_tick(Timer* timer, TimerTimestamp reference) {
if (TIMER_STATUS_RUNNING == timer->status &&
TIMER_TYPE_TIMER == timer->type &&
timer_has_finished(timer, reference)) {
timer_finish(timer, reference);
}
if (timer->status == TIMER_STATUS_RUNNING) {
timer_schedule_tick(timer);
if (TIMER_STATUS_RUNNING == timer->status) {
timers_mark_updated();
}
timers_mark_updated();
}

static void timer_finish(Timer* timer) {
timer->status = TIMER_STATUS_DONE;
timer_completed_action(timer);
}

static void timer_schedule_tick(Timer* timer) {
timer_cancel_tick(timer);
timer->timer = app_timer_register(1000, timer_tick, (void*)timer);
static bool timer_has_finished(Timer* timer, TimerTimestamp reference) {
return reference >= timer_get_end_timestamp(timer);
}

static void timer_cancel_tick(Timer* timer) {
if (! timer) {
return;
}
if (timer->timer) {
app_timer_cancel(timer->timer);
timer->timer = NULL;
static void timer_finish(Timer* timer, TimerTimestamp reference) {
timer_transition_to(timer, reference, TIMER_STATUS_DONE);
if (timer->repeat == TIMER_REPEAT_INFINITE) {
timer_restart(timer, reference);
} else {
timer_set_running_time(timer, reference, timer->length);
}
timer_completed_action(timer);
}

static void timer_schedule_wakeup(Timer* timer, uint16_t offset) {
Expand All @@ -220,8 +260,7 @@ static void timer_schedule_wakeup(Timer* timer, uint16_t offset) {
return;
}
timer_cancel_wakeup(timer);
time_t wakeup_time = time(NULL);
wakeup_time += timer->current_time;
TimerTimestamp wakeup_time = timer_get_end_timestamp(timer);
wakeup_time -= 2;
wakeup_time -= offset;
timer->wakeup_id = wakeup_schedule(wakeup_time, timer->id, false);
Expand Down Expand Up @@ -318,8 +357,5 @@ static void timer_completed_action(Timer* timer) {
default:
break;
}
if (timer->repeat == TIMER_REPEAT_INFINITE) {
timer_start(timer);
}
timers_highlight(timer);
}
21 changes: 15 additions & 6 deletions src/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,29 +54,38 @@ typedef enum {
TIMER_STATUS_DONE = 3,
} TimerStatus;

typedef time_t TimerTimestamp;

typedef struct Timer {
uint16_t id;
TimerType type;
uint32_t length;
uint32_t current_time;
int32_t paused_offset;
TimerTimestamp start_timestamp;
TimerStatus status;
TimerVibration vibration;
uint8_t repeat;
uint8_t repeat_count;
AppTimer* timer;
WakeupId wakeup_id;
char label[24];
} Timer;

#define TIMER_REPEAT_INFINITE 100

void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len);
void timer_start(Timer* timer);
void timer_pause(Timer* timer);
void timer_resume(Timer* timer);
void timer_display_str(Timer* timer, TimerTimestamp reference, bool showHours, char* str, int str_len);
void timer_start(Timer* timer, TimerTimestamp reference);
void timer_pause(Timer* timer, TimerTimestamp reference);
void timer_resume(Timer* timer, TimerTimestamp reference);
void timer_reset(Timer* timer);
void timer_restore(Timer* timer, uint16_t seconds_elapsed);
void timer_restart(Timer* timer, TimerTimestamp reference);
void timer_restore(Timer* timer, TimerTimestamp reference);
void timer_restore_legacy(Timer* timer, TimerTimestamp reference, uint32_t offset, uint32_t display_time);
Timer* timer_clone(Timer* timer);
char* timer_vibe_str(TimerVibration vibe, bool shortStr);
Timer* timer_create_timer(void);
Timer* timer_create_stopwatch(void);
void timer_tick(Timer* timer, TimerTimestamp reference);
uint32_t timer_get_running_time(Timer* timer, TimerTimestamp reference);
TimerTimestamp timer_get_end_timestamp(Timer* timer);
int32_t timer_get_display_time(Timer* timer, TimerTimestamp reference);
Loading