From 822f857d9e3bdc38985286652bec0d9cce89297d Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Mon, 2 Jan 2023 10:34:50 +0200 Subject: [PATCH] stopwatch: Update UI The time used to be yellow while paused. Changing it to white made the paused state less distinct. Blinking the time while paused makes the state distinct again. --- src/displayapp/InfiniTimeTheme.h | 1 + src/displayapp/screens/StopWatch.cpp | 131 +++++++++++++++++---------- src/displayapp/screens/StopWatch.h | 11 ++- 3 files changed, 91 insertions(+), 52 deletions(-) diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 52c339dd..99313cf0 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -5,6 +5,7 @@ namespace Colors { static constexpr lv_color_t orange = LV_COLOR_MAKE(0xff, 0xb0, 0x0); static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0); + static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff); static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index c68cd854..a094c6e0 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -18,51 +18,60 @@ namespace { void play_pause_event_handler(lv_obj_t* obj, lv_event_t event) { auto* stopWatch = static_cast(obj->user_data); - stopWatch->playPauseBtnEventHandler(event); + if (event == LV_EVENT_CLICKED) { + stopWatch->playPauseBtnEventHandler(); + } } void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) { auto* stopWatch = static_cast(obj->user_data); - stopWatch->stopLapBtnEventHandler(event); + if (event == LV_EVENT_CLICKED) { + stopWatch->stopLapBtnEventHandler(); + } } + + constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000); } StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) : Screen(app), systemTask {systemTask} { - - time = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_label_set_text_static(time, "00:00"); - lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45); - - msecTime = lv_label_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_label_set_text_static(msecTime, "00"); - lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3); - + static constexpr uint8_t btnWidth = 115; + static constexpr uint8_t btnHeight = 80; btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler); - lv_obj_set_size(btnPlayPause, 115, 50); + lv_obj_set_size(btnPlayPause, btnWidth, btnHeight); lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); txtPlayPause = lv_label_create(btnPlayPause, nullptr); - lv_label_set_text_static(txtPlayPause, Symbols::play); btnStopLap = lv_btn_create(lv_scr_act(), nullptr); btnStopLap->user_data = this; lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler); - lv_obj_set_size(btnStopLap, 115, 50); + lv_obj_set_size(btnStopLap, btnWidth, btnHeight); lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); txtStopLap = lv_label_create(btnStopLap, nullptr); - lv_label_set_text_static(txtStopLap, Symbols::stop); lv_obj_set_state(btnStopLap, LV_STATE_DISABLED); lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); lapText = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(lapText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); - lv_obj_align(lapText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30); - lv_label_set_text_static(lapText, ""); + lv_obj_set_style_local_text_color(lapText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_label_set_text_static(lapText, "\n"); + lv_label_set_long_mode(lapText, LV_LABEL_LONG_BREAK); + lv_label_set_align(lapText, LV_LABEL_ALIGN_CENTER); + lv_obj_set_width(lapText, LV_HOR_RES_MAX); + lv_obj_align(lapText, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -btnHeight); + + msecTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(msecTime, "00"); + lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, Colors::lightGray); + lv_obj_align(msecTime, lapText, LV_ALIGN_OUT_TOP_MID, 0, 0); + + time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_static(time, "00:00"); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, Colors::lightGray); + lv_obj_align(time, msecTime, LV_ALIGN_OUT_TOP_MID, 0, 0); + + SetInterfaceStopped(); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } @@ -73,42 +82,62 @@ StopWatch::~StopWatch() { lv_obj_clean(lv_scr_act()); } -void StopWatch::Reset() { - currentState = States::Init; - oldTimeElapsed = 0; - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); +void StopWatch::SetInterfacePaused() { + lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::blue); + lv_label_set_text_static(txtPlayPause, Symbols::play); + lv_label_set_text_static(txtStopLap, Symbols::stop); +} + +void StopWatch::SetInterfaceRunning() { + lv_obj_set_state(time, LV_STATE_DEFAULT); + lv_obj_set_state(msecTime, LV_STATE_DEFAULT); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + + lv_label_set_text_static(txtPlayPause, Symbols::pause); + lv_label_set_text_static(txtStopLap, Symbols::lapsFlag); + + lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); + lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); +} + +void StopWatch::SetInterfaceStopped() { + lv_obj_set_state(time, LV_STATE_DISABLED); + lv_obj_set_state(msecTime, LV_STATE_DISABLED); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::blue); lv_label_set_text_static(time, "00:00"); lv_label_set_text_static(msecTime, "00"); lv_label_set_text_static(lapText, ""); - lapsDone = 0; + lv_label_set_text_static(txtPlayPause, Symbols::play); + lv_label_set_text_static(txtStopLap, Symbols::lapsFlag); lv_obj_set_state(btnStopLap, LV_STATE_DISABLED); lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); } +void StopWatch::Reset() { + SetInterfaceStopped(); + currentState = States::Init; + oldTimeElapsed = 0; + lapsDone = 0; +} + void StopWatch::Start() { - lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); - lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); - lv_label_set_text_static(txtPlayPause, Symbols::pause); - lv_label_set_text_static(txtStopLap, Symbols::lapsFlag); + SetInterfaceRunning(); startTime = xTaskGetTickCount(); currentState = States::Running; systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); } void StopWatch::Pause() { + SetInterfacePaused(); startTime = 0; // Store the current time elapsed in cache oldTimeElapsed = laps[lapsDone]; + blinkTime = xTaskGetTickCount() + blinkInterval; currentState = States::Halted; - lv_label_set_text_static(txtPlayPause, Symbols::play); - lv_label_set_text_static(txtStopLap, Symbols::stop); - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); } @@ -119,26 +148,30 @@ void StopWatch::Refresh() { TimeSeparated_t currentTimeSeparated = convertTicksToTimeSegments(laps[lapsDone]); lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); + } else if (currentState == States::Halted) { + const TickType_t currentTime = xTaskGetTickCount(); + if (currentTime > blinkTime) { + blinkTime = currentTime + blinkInterval; + if (lv_obj_get_state(time, LV_LABEL_PART_MAIN) == LV_STATE_DEFAULT) { + lv_obj_set_state(time, LV_STATE_DISABLED); + lv_obj_set_state(msecTime, LV_STATE_DISABLED); + } else { + lv_obj_set_state(time, LV_STATE_DEFAULT); + lv_obj_set_state(msecTime, LV_STATE_DEFAULT); + } + } } } -void StopWatch::playPauseBtnEventHandler(lv_event_t event) { - if (event != LV_EVENT_CLICKED) { - return; - } - if (currentState == States::Init) { +void StopWatch::playPauseBtnEventHandler() { + if (currentState == States::Init || currentState == States::Halted) { Start(); } else if (currentState == States::Running) { Pause(); - } else if (currentState == States::Halted) { - Start(); } } -void StopWatch::stopLapBtnEventHandler(lv_event_t event) { - if (event != LV_EVENT_CLICKED) { - return; - } +void StopWatch::stopLapBtnEventHandler() { // If running, then this button is used to save laps if (currentState == States::Running) { lv_label_set_text(lapText, ""); diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index f2f57110..ce9d0fea 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -24,19 +24,24 @@ namespace Pinetime::Applications::Screens { ~StopWatch() override; void Refresh() override; - void playPauseBtnEventHandler(lv_event_t event); - void stopLapBtnEventHandler(lv_event_t event); + void playPauseBtnEventHandler(); + void stopLapBtnEventHandler(); bool OnButtonPushed() override; + private: + void SetInterfacePaused(); + void SetInterfaceRunning(); + void SetInterfaceStopped(); + void Reset(); void Start(); void Pause(); - private: Pinetime::System::SystemTask& systemTask; States currentState = States::Init; TickType_t startTime; TickType_t oldTimeElapsed = 0; + TickType_t blinkTime = 0; static constexpr int maxLapCount = 20; TickType_t laps[maxLapCount + 1]; static constexpr int displayedLaps = 2;