#include "countdown_view.h" #include "../utils/utils.h" // internal static void handle_misc_cmd(CountDownTimView* hw, CountDownViewCmd cmd); static void handle_time_setting_updown(CountDownTimView* cdv, CountDownViewCmd cmd); static void handle_time_setting_select(InputKey key, CountDownTimView* cdv); static void draw_selection(Canvas* canvas, CountDownViewSelect selection); static void countdown_timer_start_counting(CountDownTimView* cdv); static void countdown_timer_pause_counting(CountDownTimView* cdv); // callbacks static void countdown_timer_view_on_enter(void* ctx); static void countdown_timer_view_on_draw(Canvas* canvas, void* ctx); static bool countdown_timer_view_on_input(InputEvent* event, void* ctx); static void timer_cb(void* ctx); CountDownTimView* countdown_timer_view_new() { CountDownTimView* cdv = (CountDownTimView*)(malloc(sizeof(CountDownTimView))); cdv->view = view_alloc(); cdv->timer = furi_timer_alloc(timer_cb, FuriTimerTypePeriodic, cdv); cdv->counting = false; view_set_context(cdv->view, cdv); view_allocate_model(cdv->view, ViewModelTypeLocking, sizeof(CountDownModel)); view_set_draw_callback(cdv->view, countdown_timer_view_on_draw); view_set_input_callback(cdv->view, countdown_timer_view_on_input); view_set_enter_callback(cdv->view, countdown_timer_view_on_enter); return cdv; } void countdown_timer_view_delete(CountDownTimView* cdv) { furi_assert(cdv); view_free(cdv->view); furi_timer_stop(cdv->timer); furi_timer_free(cdv->timer); free(cdv); } View* countdown_timer_view_get_view(CountDownTimView* cdv) { return cdv->view; } void countdown_timer_view_state_reset(CountDownTimView* cdv) { cdv->counting = false; with_view_model( cdv->view, CountDownModel * model, { model->count = model->saved_count_setting; }, true) } void countdown_timer_state_toggle(CountDownTimView* cdv) { bool on = cdv->counting; if(!on) { countdown_timer_start_counting(cdv); } else { countdown_timer_pause_counting(cdv); } cdv->counting = !on; } // on enter callback, CountDownTimView as ctx static void countdown_timer_view_on_enter(void* ctx) { furi_assert(ctx); CountDownTimView* cdv = (CountDownTimView*)ctx; // set current count to a initial value with_view_model( cdv->view, CountDownModel * model, { model->count = INIT_COUNT; model->saved_count_setting = INIT_COUNT; }, true); } // view draw callback, CountDownModel as ctx static void countdown_timer_view_on_draw(Canvas* canvas, void* ctx) { furi_assert(ctx); CountDownModel* model = (CountDownModel*)ctx; char buffer[64]; int32_t count = model->count; int32_t expected_count = model->saved_count_setting; CountDownViewSelect select = model->select; // elements_frame(canvas, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); canvas_set_font(canvas, FontBigNumbers); draw_selection(canvas, select); parse_sec_to_time_str(buffer, sizeof(buffer), count); canvas_draw_str_aligned( canvas, SCREEN_CENTER_X, SCREEN_CENTER_Y, AlignCenter, AlignCenter, buffer); elements_progress_bar(canvas, 0, 0, SCREEN_WIDTH, (1.0 * count / expected_count)); } // keys input event callback, CountDownTimView as ctx static bool countdown_timer_view_on_input(InputEvent* event, void* ctx) { furi_assert(ctx); CountDownTimView* hw = (CountDownTimView*)ctx; if(event->type == InputTypeShort || event->type == InputTypeRepeat) { switch(event->key) { case InputKeyUp: case InputKeyDown: case InputKeyRight: case InputKeyLeft: handle_time_setting_select(event->key, hw); break; case InputKeyOk: if(event->type == InputTypeShort) { handle_misc_cmd(hw, CountDownTimerToggleCounting); } break; default: break; } return true; } if(event->type == InputTypeLong) { switch(event->key) { case InputKeyOk: handle_misc_cmd(hw, CountDownTimerReset); break; case InputKeyBack: return false; break; default: break; } return true; } return false; } static void timer_cb(void* ctx) { furi_assert(ctx); CountDownTimView* cdv = (CountDownTimView*)ctx; int32_t count; bool timeup = false; // decrement counter with_view_model( cdv->view, CountDownModel * model, { count = model->count; count--; // check timeup if(count <= 0) { count = 0; timeup = true; } model->count = count; }, true); if(timeup) { handle_misc_cmd(cdv, CountDownTimerTimeUp); } } static void handle_time_setting_updown(CountDownTimView* cdv, CountDownViewCmd cmd) { int32_t count; with_view_model( cdv->view, CountDownModel * model, { count = model->count; switch(cmd) { case CountDownTimerMinuteUp: count += 60; break; case CountDownTimerMinuteDown: count -= 60; break; case CountDownTimerHourDown: count -= 3600; break; case CountDownTimerHourUp: count += 3600; break; case CountDownTimerSecUp: count++; break; case CountDownTimerSecDown: count--; break; default: break; } if(count < 0) { count = 0; } // update count state model->count = count; // save the count time setting model->saved_count_setting = count; }, true); } static void handle_misc_cmd(CountDownTimView* hw, CountDownViewCmd cmd) { switch(cmd) { case CountDownTimerTimeUp: notification_timeup(); break; case CountDownTimerReset: furi_timer_stop(hw->timer); countdown_timer_view_state_reset(hw); notification_off(); break; case CountDownTimerToggleCounting: countdown_timer_state_toggle(hw); break; default: break; } return; } static void handle_time_setting_select(InputKey key, CountDownTimView* cdv) { bool counting = cdv->counting; CountDownViewCmd setting_cmd = CountDownTimerSecUp; CountDownViewSelect selection; if(counting) { return; } // load current selection from model context with_view_model( cdv->view, CountDownModel * model, { selection = model->select; }, false); // select switch(key) { case InputKeyUp: switch(selection) { case CountDownTimerSelectSec: setting_cmd = CountDownTimerSecUp; break; case CountDownTimerSelectMinute: setting_cmd = CountDownTimerMinuteUp; break; case CountDownTimerSelectHour: setting_cmd = CountDownTimerHourUp; break; } handle_time_setting_updown(cdv, setting_cmd); break; case InputKeyDown: switch(selection) { case CountDownTimerSelectSec: setting_cmd = CountDownTimerSecDown; break; case CountDownTimerSelectMinute: setting_cmd = CountDownTimerMinuteDown; break; case CountDownTimerSelectHour: setting_cmd = CountDownTimerHourDown; break; } handle_time_setting_updown(cdv, setting_cmd); break; case InputKeyRight: selection--; selection = selection % 3; break; case InputKeyLeft: selection++; selection = selection % 3; break; default: break; } // save selection to model context with_view_model( cdv->view, CountDownModel * model, { model->select = selection; }, false); } static void draw_selection(Canvas* canvas, CountDownViewSelect selection) { switch(selection) { case CountDownTimerSelectSec: elements_slightly_rounded_box(canvas, SCREEN_CENTER_X + 25, SCREEN_CENTER_Y + 11, 24, 2); break; case CountDownTimerSelectMinute: elements_slightly_rounded_box(canvas, SCREEN_CENTER_X - 10, SCREEN_CENTER_Y + 11, 21, 2); break; case CountDownTimerSelectHour: elements_slightly_rounded_box(canvas, SCREEN_CENTER_X - 47, SCREEN_CENTER_Y + 11, 24, 2); break; } } static void countdown_timer_start_counting(CountDownTimView* cdv) { furi_timer_start(cdv->timer, furi_kernel_get_tick_frequency() * 1); // 1s } static void countdown_timer_pause_counting(CountDownTimView* cdv) { furi_timer_stop(cdv->timer); notification_off(); }