diff --git a/src/components/timer/Timer.cpp b/src/components/timer/Timer.cpp index 279178cd33..bbc80084be 100644 --- a/src/components/timer/Timer.cpp +++ b/src/components/timer/Timer.cpp @@ -7,14 +7,29 @@ Timer::Timer(void* const timerData, TimerCallbackFunction_t timerCallbackFunctio } void Timer::StartTimer(std::chrono::milliseconds duration) { - xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0); + timerOverflowIntervals = 0; + + if (duration.count() > maxTimerMS) { + timerOverflowIntervals = duration.count() / maxTimerMS; + uint32_t remainingMS = duration.count() % maxTimerMS; + uint8_t leftoverMinutes = remainingMS / 60 / 1000; + uint8_t leftoverSeconds = (remainingMS % (60 * 1000)) / 1000; + if (leftoverMinutes == 0 && leftoverSeconds == 0) { + leftoverMinutes = 59; + leftoverSeconds = 60; + timerOverflowIntervals--; + } + xTimerChangePeriod(timer, pdMS_TO_TICKS((leftoverMinutes * 60 * 1000) + (leftoverSeconds * 1000)), 0); + } else { + xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0); + } xTimerStart(timer, 0); } std::chrono::milliseconds Timer::GetTimeRemaining() { if (IsRunning()) { TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount(); - return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ); + return std::chrono::milliseconds((remainingTime * 1000 / configTICK_RATE_HZ) + (timerOverflowIntervals * maxTimerMS)); } return std::chrono::milliseconds(0); } diff --git a/src/components/timer/Timer.h b/src/components/timer/Timer.h index 2469666f4f..6099e95c2b 100644 --- a/src/components/timer/Timer.h +++ b/src/components/timer/Timer.h @@ -19,8 +19,12 @@ namespace Pinetime { bool IsRunning(); - private: + uint8_t timerOverflowIntervals = 0; + TimerHandle_t timer; + + const uint32_t maxTimerMS = 3'600'000; // 1 hour + private: }; } } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 6671ac9e51..09f7efd9f0 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -362,17 +362,22 @@ void DisplayApp::Refresh() { LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; case Messages::TimerDone: - if (state != States::Running) { - PushMessageToSystemTask(System::Messages::GoToRunning); - } - if (currentApp == Apps::Timer) { - lv_disp_trig_activity(nullptr); - auto* timer = static_cast(currentScreen.get()); - timer->Reset(); + if (timer.timerOverflowIntervals > 0) { + timer.StopTimer(); + timer.StartTimer(std::chrono::milliseconds(timer.timerOverflowIntervals * timer.maxTimerMS)); } else { - LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + if (state != States::Running) { + PushMessageToSystemTask(System::Messages::GoToRunning); + } + if (currentApp == Apps::Timer) { + lv_disp_trig_activity(nullptr); + auto* timer = static_cast(currentScreen.get()); + timer->Reset(); + } else { + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + } + motorController.RunForDuration(35); } - motorController.RunForDuration(35); break; case Messages::AlarmTriggered: if (currentApp == Apps::Alarm) { diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index f6d5e73bdc..25b0fd2a91 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -19,16 +19,24 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { Timer::Timer(Controllers::Timer& timerController) : timer {timerController} { - lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - lv_obj_set_style_local_text_color(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_label_set_text_static(colonLabel, ":"); - lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); - + lv_obj_t* colonMinutesSeconds = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonMinutesSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_obj_set_style_local_text_color(colonMinutesSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_label_set_text_static(colonMinutesSeconds, ":"); + lv_obj_align(colonMinutesSeconds, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 40, 78); + + lv_obj_t* colonHoursMinutes = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonHoursMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_obj_set_style_local_text_color(colonHoursMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_label_set_text_static(colonHoursMinutes, ":"); + lv_obj_align(colonHoursMinutes, lv_scr_act(), LV_ALIGN_IN_TOP_MID, -41, 78); + + hourCounter.Create(); minuteCounter.Create(); secondCounter.Create(); - lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 26); + lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_MID, 0, 26); + lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, -10, 26); highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr); lv_obj_set_size(highlightObjectMask, 240, 50); @@ -120,18 +128,21 @@ void Timer::Refresh() { void Timer::DisplayTime() { displaySeconds = std::chrono::duration_cast(timer.GetTimeRemaining()); if (displaySeconds.IsUpdated()) { - minuteCounter.SetValue(displaySeconds.Get().count() / 60); + hourCounter.SetValue(displaySeconds.Get().count() / 3600); + minuteCounter.SetValue((displaySeconds.Get().count() % 3600) / 60); secondCounter.SetValue(displaySeconds.Get().count() % 60); } } void Timer::SetTimerRunning() { + hourCounter.HideControls(); minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Pause"); } void Timer::SetTimerStopped() { + hourCounter.ShowControls(); minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); @@ -142,8 +153,9 @@ void Timer::ToggleRunning() { DisplayTime(); timer.StopTimer(); SetTimerStopped(); - } else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) { - auto timerDuration = std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue()); + } else if (secondCounter.GetValue() + minuteCounter.GetValue() + hourCounter.GetValue() > 0) { + std::chrono::milliseconds timerDuration = std::chrono::hours(hourCounter.GetValue()) + std::chrono::minutes(minuteCounter.GetValue()) + + std::chrono::seconds(secondCounter.GetValue()); timer.StartTimer(timerDuration); Refresh(); SetTimerRunning(); diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index a07c729b4d..710d563369 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -38,8 +38,9 @@ namespace Pinetime::Applications { lv_objmask_mask_t* highlightMask; lv_task_t* taskRefresh; - Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); - Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76); + Widgets::Counter hourCounter = Widgets::Counter(0, 99, jetbrains_mono_42); + Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_42); + Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_42); bool buttonPressing = false; lv_coord_t maskPosition = 0;