From db5d4704cc4a7361c80d1eab199af268364545c7 Mon Sep 17 00:00:00 2001 From: Jan Hustak Date: Sun, 20 Oct 2024 12:01:36 +0200 Subject: StopWatch: add persistence # Conflicts: # src/displayapp/screens/StopWatch.h --- src/displayapp/screens/StopWatch.cpp | 178 +++++++++++++++++++---------------- src/displayapp/screens/StopWatch.h | 106 +++++++++------------ 2 files changed, 142 insertions(+), 142 deletions(-) (limited to 'src/displayapp/screens') diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index ff852beb..397cd365 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -4,9 +4,10 @@ #include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; +using namespace Pinetime::Controllers; namespace { - TimeSeparated_t convertTicksToTimeSegments(const TickType_t timeElapsed) { + TimeSeparated convertTicksToTimeSegments(const TickType_t timeElapsed) { // Centiseconds const int timeElapsedCentis = timeElapsed * 100 / configTICK_RATE_HZ; @@ -14,27 +15,29 @@ namespace { const int secs = (timeElapsedCentis / 100) % 60; const int mins = ((timeElapsedCentis / 100) / 60) % 60; const int hours = ((timeElapsedCentis / 100) / 60) / 60; - return TimeSeparated_t {hours, mins, secs, hundredths}; + return TimeSeparated {hours, mins, secs, hundredths}; } void play_pause_event_handler(lv_obj_t* obj, lv_event_t event) { auto* stopWatch = static_cast(obj->user_data); if (event == LV_EVENT_CLICKED) { - stopWatch->playPauseBtnEventHandler(); + stopWatch->PlayPauseBtnEventHandler(); } } void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) { auto* stopWatch = static_cast(obj->user_data); if (event == LV_EVENT_CLICKED) { - stopWatch->stopLapBtnEventHandler(); + stopWatch->StopLapBtnEventHandler(); } } constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000); } -StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) { +StopWatch::StopWatch(System::SystemTask& systemTask, + StopWatchController& stopWatchController) + : wakeLock(systemTask), stopWatchController {stopWatchController} { static constexpr uint8_t btnWidth = 115; static constexpr uint8_t btnHeight = 80; btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); @@ -72,9 +75,28 @@ StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) { 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); + + // Figure out what the current state of the stopwatch is and select the correct display + if (stopWatchController.IsCleared()) { + DisplayCleared(); + } else { + if (stopWatchController.GetLapCount() > 0) { + RenderLaps(); + } + RenderTime(); + + if (stopWatchController.IsRunning()) { + lv_obj_set_state(btnStopLap, LV_STATE_DISABLED); + lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); + DisplayStarted(); + wakeLock.Lock(); + } else if (stopWatchController.IsPaused()) { + lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); + lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); + DisplayPaused(); + } + } } StopWatch::~StopWatch() { @@ -82,14 +104,14 @@ StopWatch::~StopWatch() { lv_obj_clean(lv_scr_act()); } -void StopWatch::SetInterfacePaused() { +void StopWatch::DisplayPaused() { 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() { +void StopWatch::DisplayStarted() { 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); @@ -102,7 +124,7 @@ void StopWatch::SetInterfaceRunning() { lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); } -void StopWatch::SetInterfaceStopped() { +void StopWatch::DisplayCleared() { 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); @@ -123,96 +145,86 @@ void StopWatch::SetInterfaceStopped() { lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); } -void StopWatch::Reset() { - SetInterfaceStopped(); - currentState = States::Init; - oldTimeElapsed = 0; - lapsDone = 0; +void StopWatch::RenderTime() { + TimeSeparated currentTimeSeparated = convertTicksToTimeSegments(stopWatchController.GetElapsedTime()); + if (currentTimeSeparated.hours == 0) { + lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); + } else { + lv_label_set_text_fmt(time, "%02d:%02d:%02d", currentTimeSeparated.hours, currentTimeSeparated.mins, currentTimeSeparated.secs); + if (!isHoursLabelUpdated) { + lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_obj_realign(time); + isHoursLabelUpdated = true; + } + } + lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); } -void StopWatch::Start() { - SetInterfaceRunning(); - startTime = xTaskGetTickCount(); - currentState = States::Running; - wakeLock.Lock(); +void StopWatch::RenderPause() { + 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::Pause() { - SetInterfacePaused(); - startTime = 0; - // Store the current time elapsed in cache - oldTimeElapsed = laps[lapsDone]; - blinkTime = xTaskGetTickCount() + blinkInterval; - currentState = States::Halted; - wakeLock.Release(); +void StopWatch::RenderLaps() { + lv_label_set_text(lapText, ""); + for (int i = 0; i < displayedLaps; i++) { + LapInfo* lap = stopWatchController.LastLap(i); + + if (lap->count != 0) { + TimeSeparated laptime = convertTicksToTimeSegments(lap->time); + char buffer[16]; + sprintf(buffer, "#%2d %2d:%02d.%02d\n", lap->count, laptime.mins, laptime.secs, laptime.hundredths); + lv_label_ins_text(lapText, LV_LABEL_POS_LAST, buffer); + } + } } void StopWatch::Refresh() { - if (currentState == States::Running) { - laps[lapsDone] = oldTimeElapsed + xTaskGetTickCount() - startTime; - - TimeSeparated_t currentTimeSeparated = convertTicksToTimeSegments(laps[lapsDone]); - if (currentTimeSeparated.hours == 0) { - lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); - } else { - lv_label_set_text_fmt(time, "%02d:%02d:%02d", currentTimeSeparated.hours, currentTimeSeparated.mins, currentTimeSeparated.secs); - if (!isHoursLabelUpdated) { - lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); - lv_obj_realign(time); - isHoursLabelUpdated = true; - } - } - 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); - } - } + if (stopWatchController.IsRunning()) { + RenderTime(); + } else if (stopWatchController.IsPaused()) { + RenderPause(); } } -void StopWatch::playPauseBtnEventHandler() { - if (currentState == States::Init || currentState == States::Halted) { - Start(); - } else if (currentState == States::Running) { - Pause(); +void StopWatch::PlayPauseBtnEventHandler() { + if (stopWatchController.IsCleared() || stopWatchController.IsPaused()) { + stopWatchController.Start(); + DisplayStarted(); + wakeLock.Lock(); + } else if (stopWatchController.IsRunning()) { + stopWatchController.Pause(); + blinkTime = xTaskGetTickCount() + blinkInterval; + DisplayPaused(); + wakeLock.Release(); } } -void StopWatch::stopLapBtnEventHandler() { - // If running, then this button is used to save laps - if (currentState == States::Running) { - lv_label_set_text(lapText, ""); - lapsDone = std::min(lapsDone + 1, maxLapCount); - for (int i = lapsDone - displayedLaps; i < lapsDone; i++) { - if (i < 0) { - lv_label_ins_text(lapText, LV_LABEL_POS_LAST, "\n"); - continue; - } - TimeSeparated_t times = convertTicksToTimeSegments(laps[i]); - char buffer[17]; - if (times.hours == 0) { - snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d.%02d\n", i + 1, times.mins, times.secs, times.hundredths); - } else { - snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d:%02d.%02d\n", i + 1, times.hours, times.mins, times.secs, times.hundredths); - } - lv_label_ins_text(lapText, LV_LABEL_POS_LAST, buffer); - } - } else if (currentState == States::Halted) { - Reset(); +void StopWatch::StopLapBtnEventHandler() { + if (stopWatchController.IsRunning()) { + stopWatchController.PushLap(); + RenderLaps(); + } else if (stopWatchController.IsPaused()) { + stopWatchController.Clear(); + DisplayCleared(); + wakeLock.Release(); } } bool StopWatch::OnButtonPushed() { - if (currentState == States::Running) { - Pause(); + if (stopWatchController.IsRunning()) { + stopWatchController.Pause(); + DisplayPaused(); + wakeLock.Release(); return true; } return false; diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index 7256dd5b..b2e85b7a 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -3,76 +3,64 @@ #include "displayapp/screens/Screen.h" #include -#include -#include "portmacro_cmsis.h" - +#include "components/stopwatch/StopWatchController.h" #include "systemtask/SystemTask.h" #include "systemtask/WakeLock.h" -#include "displayapp/apps/Apps.h" -#include "displayapp/Controllers.h" #include "Symbols.h" -namespace Pinetime { - namespace Applications { - namespace Screens { - - enum class States { Init, Running, Halted }; - - struct TimeSeparated_t { - int hours; - int mins; - int secs; - int hundredths; - }; +namespace Pinetime::Applications { + namespace Screens { - class StopWatch : public Screen { - public: - explicit StopWatch(System::SystemTask& systemTask); - ~StopWatch() override; - void Refresh() override; - - void playPauseBtnEventHandler(); - void stopLapBtnEventHandler(); - bool OnButtonPushed() override; + struct TimeSeparated { + int hours; + int mins; + int secs; + int hundredths; + }; - private: - void SetInterfacePaused(); - void SetInterfaceRunning(); - void SetInterfaceStopped(); + class StopWatch : public Screen { + public: + explicit StopWatch(System::SystemTask& systemTask, + Controllers::StopWatchController& stopWatchController); + ~StopWatch() override; + void Refresh() override; - void Reset(); - void Start(); - void Pause(); + void PlayPauseBtnEventHandler(); + void StopLapBtnEventHandler(); + bool OnButtonPushed() override; - Pinetime::System::WakeLock wakeLock; - 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; - int lapsDone = 0; - lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; - lv_obj_t* lapText; - bool isHoursLabelUpdated = false; + private: + void DisplayPaused(); + void DisplayStarted(); + void DisplayCleared(); - lv_task_t* taskRefresh; - }; - } + void RenderTime(); + void RenderPause(); + void RenderLaps(); - template <> - struct AppTraits { - static constexpr Apps app = Apps::StopWatch; - static constexpr const char* icon = Screens::Symbols::stopWatch; + Pinetime::System::WakeLock wakeLock; + Controllers::StopWatchController& stopWatchController; + TickType_t blinkTime = 0; + static constexpr int displayedLaps = 2; + lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; + lv_obj_t* lapText; + bool isHoursLabelUpdated = false; - static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::StopWatch(*controllers.systemTask); - }; - - static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { - return true; - }; + lv_task_t* taskRefresh; }; } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::StopWatch; + static constexpr const char* icon = Screens::Symbols::stopWatch; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::StopWatch(*controllers.systemTask, + controllers.stopWatchController); + } + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; } -- cgit v1.2.3-70-g09d2