mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2024-10-22 15:11:51 +02:00
Timer: Remember last timer setting
Remember last duration used in Timer app. Stop with long press while paused. Reset to zero with long press while stopped.
This commit is contained in:
parent
f8f8993fac
commit
62b2a4d1db
|
@ -3,26 +3,57 @@
|
|||
using namespace Pinetime::Controllers;
|
||||
|
||||
Timer::Timer(void* const timerData, TimerCallbackFunction_t timerCallbackFunction) {
|
||||
pausedAtTimer = std::chrono::seconds(0);
|
||||
state = Stopped;
|
||||
timer = xTimerCreate("Timer", 1, pdFALSE, timerData, timerCallbackFunction);
|
||||
}
|
||||
|
||||
void Timer::StartTimer(std::chrono::milliseconds duration) {
|
||||
xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0);
|
||||
xTimerStart(timer, 0);
|
||||
}
|
||||
|
||||
std::chrono::milliseconds Timer::GetTimeRemaining() {
|
||||
if (IsRunning()) {
|
||||
TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
|
||||
const TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
|
||||
return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ);
|
||||
}
|
||||
|
||||
if (state == Paused)
|
||||
return pausedAtTimer;
|
||||
|
||||
return std::chrono::milliseconds(0);
|
||||
}
|
||||
|
||||
void Timer::StopTimer() {
|
||||
xTimerStop(timer, 0);
|
||||
Timer::TimerState Timer::GetState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
void Timer::Start(const std::chrono::milliseconds duration) {
|
||||
TimerStart(duration);
|
||||
state = Running;
|
||||
}
|
||||
|
||||
void Timer::Stop() {
|
||||
TimerStop();
|
||||
state = Stopped;
|
||||
}
|
||||
|
||||
void Timer::Pause() {
|
||||
pausedAtTimer = GetTimeRemaining();
|
||||
TimerStop();
|
||||
state = Paused;
|
||||
}
|
||||
|
||||
void Timer::Resume() {
|
||||
TimerStart(pausedAtTimer);
|
||||
state = Running;
|
||||
}
|
||||
|
||||
bool Timer::IsRunning() {
|
||||
return (xTimerIsTimerActive(timer) == pdTRUE);
|
||||
};
|
||||
|
||||
void Timer::TimerStart(const std::chrono::milliseconds duration) {
|
||||
xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0);
|
||||
xTimerStart(timer, 0);
|
||||
}
|
||||
|
||||
void Timer::TimerStop() {
|
||||
xTimerStop(timer, 0);
|
||||
}
|
||||
|
|
|
@ -11,16 +11,30 @@ namespace Pinetime {
|
|||
public:
|
||||
Timer(void* timerData, TimerCallbackFunction_t timerCallbackFunction);
|
||||
|
||||
void StartTimer(std::chrono::milliseconds duration);
|
||||
void Start(const std::chrono::milliseconds duration);
|
||||
|
||||
void StopTimer();
|
||||
void Stop();
|
||||
|
||||
void Pause();
|
||||
|
||||
void Resume();
|
||||
|
||||
std::chrono::milliseconds GetTimeRemaining();
|
||||
|
||||
bool IsRunning();
|
||||
typedef enum TimerState { Running, Stopped, Paused } TimerState;
|
||||
|
||||
TimerState GetState();
|
||||
|
||||
private:
|
||||
TimerHandle_t timer;
|
||||
|
||||
std::chrono::milliseconds pausedAtTimer;
|
||||
|
||||
TimerState state;
|
||||
|
||||
bool IsRunning();
|
||||
void TimerStart(const std::chrono::milliseconds duration);
|
||||
void TimerStop();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,11 +265,12 @@ void DisplayApp::Refresh() {
|
|||
}
|
||||
if (currentApp == Apps::Timer) {
|
||||
lv_disp_trig_activity(nullptr);
|
||||
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
|
||||
timer->Reset();
|
||||
} else {
|
||||
LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up);
|
||||
}
|
||||
Screens::Timer* timer;
|
||||
timer = static_cast<Screens::Timer*>(currentScreen.get());
|
||||
timer->Stop();
|
||||
motorController.RunForDuration(35);
|
||||
break;
|
||||
case Messages::AlarmTriggered:
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
static std::chrono::milliseconds lastTimerSetting;
|
||||
|
||||
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto* screen = static_cast<Timer*>(obj->user_data);
|
||||
if (event == LV_EVENT_PRESSED) {
|
||||
|
@ -17,6 +19,11 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
|
|||
}
|
||||
}
|
||||
|
||||
static void counterChangeHandler(void *timerScreen) {
|
||||
Timer* timer = (Timer*)timerScreen;
|
||||
lastTimerSetting = timer->GetCounters();
|
||||
}
|
||||
|
||||
Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
|
||||
|
||||
lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
@ -29,6 +36,8 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
|
|||
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);
|
||||
minuteCounter.SetValueChangedEventCallback(this, counterChangeHandler);
|
||||
secondCounter.SetValueChangedEventCallback(this, counterChangeHandler);
|
||||
|
||||
highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_size(highlightObjectMask, 240, 50);
|
||||
|
@ -60,12 +69,20 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
|
|||
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
|
||||
|
||||
txtPlayPause = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
if (timer.IsRunning()) {
|
||||
SetTimerRunning();
|
||||
} else {
|
||||
SetTimerStopped();
|
||||
switch (timer.GetState()) {
|
||||
case Controllers::Timer::TimerState::Stopped:
|
||||
SetCounters(lastTimerSetting);
|
||||
SetInterfaceStopped();
|
||||
break;
|
||||
case Controllers::Timer::TimerState::Running:
|
||||
SetCounters(timer.GetTimeRemaining());
|
||||
SetInterfaceRunning();
|
||||
break;
|
||||
case Controllers::Timer::TimerState::Paused:
|
||||
SetCounters(timer.GetTimeRemaining());
|
||||
SetInterfacePaused();
|
||||
break;
|
||||
}
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
|
@ -76,6 +93,11 @@ Timer::~Timer() {
|
|||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void Timer::SetButtonText(const char* text) {
|
||||
lv_label_set_text_static(txtPlayPause, text);
|
||||
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void Timer::ButtonPressed() {
|
||||
pressTime = xTaskGetTickCount();
|
||||
buttonPressing = true;
|
||||
|
@ -83,15 +105,40 @@ void Timer::ButtonPressed() {
|
|||
|
||||
void Timer::MaskReset() {
|
||||
buttonPressing = false;
|
||||
|
||||
// A click event is processed before a release event,
|
||||
// so the release event would override the "Pause" text without this check
|
||||
if (!timer.IsRunning()) {
|
||||
lv_label_set_text_static(txtPlayPause, "Start");
|
||||
switch (timer.GetState()) {
|
||||
case Controllers::Timer::TimerState::Stopped:
|
||||
SetButtonText("Start");
|
||||
break;
|
||||
case Controllers::Timer::TimerState::Running:
|
||||
SetButtonText("Pause");
|
||||
break;
|
||||
case Controllers::Timer::TimerState::Paused:
|
||||
SetButtonText("Resume");
|
||||
break;
|
||||
}
|
||||
|
||||
maskPosition = 0;
|
||||
UpdateMask();
|
||||
}
|
||||
|
||||
void Timer::HandleHold() {
|
||||
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
|
||||
SetButtonText("Reset");
|
||||
} else {
|
||||
SetButtonText("Stop");
|
||||
}
|
||||
|
||||
maskPosition += 15;
|
||||
if (maskPosition > 240) {
|
||||
HandleLongPress();
|
||||
} else {
|
||||
UpdateMask();
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::UpdateMask() {
|
||||
lv_draw_mask_line_param_t maskLine;
|
||||
|
||||
|
@ -102,52 +149,81 @@ void Timer::UpdateMask() {
|
|||
lv_objmask_update_mask(btnObjectMask, btnMask, &maskLine);
|
||||
}
|
||||
|
||||
void Timer::HandleLongPress() {
|
||||
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
|
||||
Reset();
|
||||
} else {
|
||||
Stop();
|
||||
}
|
||||
|
||||
MaskReset();
|
||||
}
|
||||
|
||||
void Timer::Refresh() {
|
||||
if (timer.IsRunning()) {
|
||||
if (timer.GetState() == Controllers::Timer::TimerState::Running) {
|
||||
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
|
||||
minuteCounter.SetValue(secondsRemaining.count() / 60);
|
||||
secondCounter.SetValue(secondsRemaining.count() % 60);
|
||||
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
|
||||
lv_label_set_text_static(txtPlayPause, "Reset");
|
||||
maskPosition += 15;
|
||||
if (maskPosition > 240) {
|
||||
MaskReset();
|
||||
Reset();
|
||||
} else {
|
||||
UpdateMask();
|
||||
SetCounters(secondsRemaining);
|
||||
} else {
|
||||
if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
|
||||
HandleHold();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::SetTimerRunning() {
|
||||
void Timer::SetInterfaceRunning() {
|
||||
minuteCounter.HideControls();
|
||||
secondCounter.HideControls();
|
||||
lv_label_set_text_static(txtPlayPause, "Pause");
|
||||
SetButtonText("Pause");
|
||||
}
|
||||
|
||||
void Timer::SetTimerStopped() {
|
||||
void Timer::SetInterfacePaused() {
|
||||
minuteCounter.HideControls();
|
||||
secondCounter.HideControls();
|
||||
SetButtonText("Resume");
|
||||
}
|
||||
|
||||
void Timer::SetInterfaceStopped() {
|
||||
minuteCounter.ShowControls();
|
||||
secondCounter.ShowControls();
|
||||
lv_label_set_text_static(txtPlayPause, "Start");
|
||||
SetButtonText("Start");
|
||||
}
|
||||
|
||||
void Timer::SetCounters(const std::chrono::milliseconds& duration) {
|
||||
SetCounters(std::chrono::duration_cast<std::chrono::seconds>(duration));
|
||||
}
|
||||
|
||||
void Timer::SetCounters(const std::chrono::seconds& duration) {
|
||||
minuteCounter.SetValue(duration.count() / 60);
|
||||
secondCounter.SetValue(duration.count() % 60);
|
||||
}
|
||||
|
||||
std::chrono::seconds Timer::GetCounters() {
|
||||
return std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue());
|
||||
}
|
||||
|
||||
void Timer::ToggleRunning() {
|
||||
if (timer.IsRunning()) {
|
||||
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
|
||||
minuteCounter.SetValue(secondsRemaining.count() / 60);
|
||||
secondCounter.SetValue(secondsRemaining.count() % 60);
|
||||
timer.StopTimer();
|
||||
SetTimerStopped();
|
||||
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
|
||||
auto timerDuration = std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue());
|
||||
timer.StartTimer(timerDuration);
|
||||
Refresh();
|
||||
SetTimerRunning();
|
||||
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
|
||||
if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
|
||||
timer.Start(GetCounters());
|
||||
Refresh();
|
||||
SetInterfaceRunning();
|
||||
}
|
||||
} else if (timer.GetState() == Controllers::Timer::TimerState::Running) {
|
||||
timer.Pause();
|
||||
SetInterfacePaused();
|
||||
} else { // Paused
|
||||
timer.Resume();
|
||||
SetInterfaceRunning();
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::Reset() {
|
||||
minuteCounter.SetValue(0);
|
||||
secondCounter.SetValue(0);
|
||||
SetTimerStopped();
|
||||
lastTimerSetting = std::chrono::seconds(0);
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Timer::Stop() {
|
||||
timer.Stop();
|
||||
SetCounters(lastTimerSetting);
|
||||
SetInterfaceStopped();
|
||||
}
|
||||
|
|
|
@ -17,15 +17,23 @@ namespace Pinetime::Applications {
|
|||
Timer(Controllers::Timer& timerController);
|
||||
~Timer() override;
|
||||
void Refresh() override;
|
||||
void Stop();
|
||||
void Reset();
|
||||
void ToggleRunning();
|
||||
void ButtonPressed();
|
||||
void MaskReset();
|
||||
std::chrono::seconds GetCounters();
|
||||
|
||||
private:
|
||||
void SetTimerRunning();
|
||||
void SetTimerStopped();
|
||||
void SetInterfaceRunning();
|
||||
void SetInterfacePaused();
|
||||
void SetInterfaceStopped();
|
||||
void HandleHold();
|
||||
void UpdateMask();
|
||||
void HandleLongPress();
|
||||
void SetCounters(const std::chrono::milliseconds& duration);
|
||||
void SetCounters(const std::chrono::seconds& duration);
|
||||
void SetButtonText(const char* text);
|
||||
Pinetime::Controllers::Timer& timer;
|
||||
|
||||
lv_obj_t* btnPlayPause;
|
||||
|
|
Loading…
Reference in a new issue