diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e32cd043..64cbada3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -366,6 +366,7 @@ list(APPEND SOURCE_FILES displayapp/DisplayApp.cpp displayapp/screens/Screen.cpp displayapp/screens/Tile.cpp + displayapp/screens/Bird.cpp displayapp/screens/InfiniPaint.cpp displayapp/screens/Paddle.cpp displayapp/screens/StopWatch.cpp @@ -377,6 +378,7 @@ list(APPEND SOURCE_FILES displayapp/screens/FirmwareUpdate.cpp displayapp/screens/Music.cpp displayapp/screens/Navigation.cpp + displayapp/screens/Calendar.cpp displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp displayapp/screens/Weather.cpp @@ -384,6 +386,7 @@ list(APPEND SOURCE_FILES displayapp/screens/ApplicationList.cpp displayapp/screens/Notifications.cpp displayapp/screens/Twos.cpp + displayapp/screens/Bird.cpp displayapp/screens/HeartRate.cpp displayapp/screens/FlashLight.cpp displayapp/screens/List.cpp diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 96963381..c8f6f050 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -87,6 +87,10 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } +bool MotorController::IsRinging() { + return (xTimerIsTimerActive(longVib) == pdTRUE); +} + void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 2f6ca59b..0a013351 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -17,6 +17,7 @@ namespace Pinetime { void StopRinging(); void PatternFinished(); bool StartPattern(); + bool IsRinging(); private: static void Ring(TimerHandle_t xTimer); diff --git a/src/components/timer/Timer.cpp b/src/components/timer/Timer.cpp index 279178cd..b3c4417a 100644 --- a/src/components/timer/Timer.cpp +++ b/src/components/timer/Timer.cpp @@ -12,11 +12,13 @@ void Timer::StartTimer(std::chrono::milliseconds duration) { } std::chrono::milliseconds Timer::GetTimeRemaining() { + TickType_t remainingTime = 0; if (IsRunning()) { - TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount(); - return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ); + remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount(); + } else { + remainingTime = xTaskGetTickCount() - xTimerGetExpiryTime(timer); } - return std::chrono::milliseconds(0); + return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ); } void Timer::StopTimer() { diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 354fc102..76076e2c 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -14,11 +14,14 @@ #include "displayapp/screens/FirmwareUpdate.h" #include "displayapp/screens/FirmwareValidation.h" #include "displayapp/screens/InfiniPaint.h" +#include "displayapp/screens/Bird.h" #include "displayapp/screens/Paddle.h" +#include "displayapp/screens/Bird.h" #include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Metronome.h" #include "displayapp/screens/Music.h" #include "displayapp/screens/Navigation.h" +#include "displayapp/screens/Calendar.h" #include "displayapp/screens/Notifications.h" #include "displayapp/screens/SystemInfo.h" #include "displayapp/screens/Tile.h" @@ -267,14 +270,17 @@ void DisplayApp::Refresh() { if (state != States::Running) { PushMessageToSystemTask(System::Messages::GoToRunning); } + // Load timer app if not loaded + if (currentApp != Apps::Timer) { + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + } + // Once loaded, set the timer to ringing mode if (currentApp == Apps::Timer) { lv_disp_trig_activity(nullptr); auto* timer = static_cast(currentScreen.get()); - timer->Reset(); - } else { - LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + timer->SetTimerRinging(); } - motorController.RunForDuration(35); + motorController.StartRinging(); break; case Messages::AlarmTriggered: if (currentApp == Apps::Alarm) { @@ -312,7 +318,7 @@ void DisplayApp::Refresh() { }; if (!currentScreen->OnTouchEvent(gesture)) { - if (currentApp == Apps::Clock || currentApp == Apps::Music || currentApp == Apps::Calculator || currentApp == Apps::QuickSettings) { + if (currentApp == Apps::Clock || currentApp == Apps::Music || currentApp == Apps::Weather || currentApp == Apps::QuickSettings) { switch (gesture) { case TouchEvents::SwipeUp: if (currentApp == Apps::Clock) { @@ -335,8 +341,8 @@ void DisplayApp::Refresh() { if (currentApp == Apps::Clock) { LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); } else if (currentApp == Apps::QuickSettings) { - LoadNewScreen(Apps::Calculator, DisplayApp::FullRefreshDirections::RightAnim); - } else if (currentApp == Apps::Calculator) { + LoadNewScreen(Apps::Weather, DisplayApp::FullRefreshDirections::RightAnim); + } else if (currentApp == Apps::Weather) { LoadNewScreen(Apps::Music, DisplayApp::FullRefreshDirections::RightAnim); } else { LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::RightAnim); @@ -346,8 +352,8 @@ void DisplayApp::Refresh() { if (currentApp == Apps::Clock) { LoadNewScreen(Apps::Music, DisplayApp::FullRefreshDirections::LeftAnim); } else if (currentApp == Apps::Music) { - LoadNewScreen(Apps::Calculator, DisplayApp::FullRefreshDirections::LeftAnim); - } else if (currentApp == Apps::Calculator) { + LoadNewScreen(Apps::Weather, DisplayApp::FullRefreshDirections::LeftAnim); + } else if (currentApp == Apps::Weather) { LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::LeftAnim); } else { LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 0690b099..57680e87 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -8,6 +8,7 @@ namespace Colors { 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 gray = LV_COLOR_MAKE(0x50, 0x50, 0x50); static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 5b8ba076..1d78799c 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -21,8 +21,10 @@ namespace Pinetime { Paint, Paddle, Twos, + Bird, HeartRate, Navigation, + Calendar, StopWatch, Metronome, Motion, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 7b909124..f23c845a 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -5,16 +5,18 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Bird") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calculator") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calculator") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calendar") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index fea31605..089df7bb 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a, 0xf4ba, 0xf073" } ], "bpp": 1, diff --git a/src/displayapp/screens/Bird.cpp b/src/displayapp/screens/Bird.cpp new file mode 100644 index 00000000..d2d78fde --- /dev/null +++ b/src/displayapp/screens/Bird.cpp @@ -0,0 +1,143 @@ +#include "displayapp/screens/Bird.h" +#include "displayapp/DisplayApp.h" +#include "displayapp/LittleVgl.h" +#include "displayapp/screens/Symbols.h" + +#include // for rand() + +using namespace Pinetime::Applications::Screens; + +Bird::Bird() { + + lv_obj_t* background = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(background, LV_HOR_RES, LV_VER_RES); + lv_obj_set_style_local_radius(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x2874a6)); + + cactus_top = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(cactus_top, CACTUS_WIDTH, CACTUS_HEIGHT); + lv_obj_set_style_local_bg_color(cactus_top, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + lv_obj_set_style_local_border_color(cactus_top, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_border_width(cactus_top, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 1); + + cactus_bottom = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(cactus_bottom, CACTUS_WIDTH, CACTUS_HEIGHT); + lv_obj_set_style_local_bg_color(cactus_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + lv_obj_set_style_local_border_color(cactus_bottom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_border_width(cactus_bottom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 1); + + MovePipe(); + + points = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(points, " "); + lv_obj_align(points, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -10, 5); + + info = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(info, "touch to start"); + lv_obj_align(info, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 40); + + bird = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(bird, Symbols::dove); + lv_obj_set_style_local_text_color(bird, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_obj_set_pos(bird, BIRD_X, pos); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); +} + +Bird::~Bird() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void Bird::MovePipe() { + lv_obj_set_pos(cactus_top, cactus_x, -cactus_y_offset); + lv_obj_set_pos(cactus_bottom, cactus_x, CACTUS_HEIGHT + CACTUS_GAP - cactus_y_offset); + return; +} + +void Bird::Refresh() { + if (is_stopped) { + return; + } + + pos += accel / 6; + + if (is_ascending) { + if (accel >= -18) { + accel -= 3; + } + } else { + if (accel <= 42) { + accel++; + } + } + + // checks if it has hit the floor or ceiling + if (pos <= 1 || pos >= LV_VER_RES - BIRD_SIZE) { + GameOver(); + return; + } + + // checks if it has rammed into cacti + // BIRD_X-CACTUS_WIDTH to BIRD_X+BIRD_SIZE + if (90 < cactus_x && cactus_x < 130) { + if (pos < CACTUS_HEIGHT - cactus_y_offset || pos > CACTUS_HEIGHT + CACTUS_GAP - BIRD_SIZE - cactus_y_offset) { + GameOver(); + return; + } + } + + lv_obj_set_pos(bird, BIRD_X, pos); + + lv_label_set_text_fmt(points, "%04d", score / 10); + is_ascending = false; + + score++; + if (cactus_x == 0) { + while (true) { + uint8_t new_offset = rand() % 5 * 40; + if (new_offset != cactus_y_offset) { + cactus_y_offset = new_offset; + break; + } + } + cactus_x = 240; + } + cactus_x--; + if (cactus_x % 4 == 0) { + MovePipe(); + } +} + +void Bird::GameOver() { + is_stopped = true; + lv_label_set_text_static(info, "Game Over"); + lv_obj_align(info, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 40); + lv_obj_set_style_local_text_color(bird, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + return; +} + +bool Bird::OnTouchEvent(Pinetime::Applications::TouchEvents /*event*/) { + if (is_stopped) { + if (pos != 120) { + pos = 120; + lv_label_set_text_static(info, "Touch to Start"); + lv_obj_align(info, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 40); + lv_obj_set_style_local_text_color(bird, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + return true; + } + // reset + cactus_x = 240; + accel = 0; + score = 0; + is_stopped = false; + lv_label_set_text_static(info, ""); + } + is_ascending = true; + return true; +} + +bool Bird::OnTouchEvent(uint16_t /*x*/, uint16_t /*y*/) { + is_ascending = true; + return true; +} diff --git a/src/displayapp/screens/Bird.h b/src/displayapp/screens/Bird.h new file mode 100644 index 00000000..b6d44d30 --- /dev/null +++ b/src/displayapp/screens/Bird.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include "displayapp/screens/Screen.h" +#include "Symbols.h" +#include "systemtask/SystemTask.h" + +#define BIRD_X 110 +#define BIRD_SIZE 20 +#define CACTUS_HEIGHT 160 +#define CACTUS_WIDTH 30 +#define CACTUS_GAP 80 + +namespace Pinetime { + namespace Components { + class LittleVgl; + } + + namespace Applications { + namespace Screens { + + class Bird : public Screen { + public: + Bird(); + ~Bird() override; + + void Refresh() override; + + bool OnTouchEvent(TouchEvents event) override; + bool OnTouchEvent(uint16_t x, uint16_t y) override; + + private: + void GameOver(); + void MovePipe(); + + bool is_stopped = true; + bool is_ascending = false; + + uint8_t cactus_x = 240; + uint8_t cactus_y_offset = 40; + + int8_t accel = 0; + uint8_t pos = 120; + uint16_t score = 0; + + lv_obj_t *info, *points, *bird, *cactus_top, *cactus_bottom; + + lv_task_t* taskRefresh; + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Bird; + static constexpr const char* icon = Screens::Symbols::dove; + + static Screens::Screen* Create(AppControllers& /*controllers*/) { + return new Screens::Bird(); + }; + }; + } +} diff --git a/src/displayapp/screens/Calendar.cpp b/src/displayapp/screens/Calendar.cpp new file mode 100644 index 00000000..43643f6c --- /dev/null +++ b/src/displayapp/screens/Calendar.cpp @@ -0,0 +1,96 @@ +/* Copyright (C) 2024 thnikk, Boteium, JustScott + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "displayapp/screens/Calendar.h" +#include "components/datetime/DateTimeController.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +Calendar::Calendar(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} { + + // Create calendar object + calendar = lv_calendar_create(lv_scr_act(), NULL); + // Set size + lv_obj_set_size(calendar, LV_HOR_RES, LV_VER_RES); + // Set alignment + lv_obj_align(calendar, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -5); + // Disable clicks + lv_obj_set_click(calendar, false); + + // Set style of today's date + lv_obj_set_style_local_text_color(calendar, LV_CALENDAR_PART_DATE, LV_STATE_FOCUSED, Colors::deepOrange); + + // Set style of inactive month's days + lv_obj_set_style_local_text_color(calendar, LV_CALENDAR_PART_DATE, LV_STATE_DISABLED, Colors::gray); + + // Get today's date + current.year = static_cast(dateTimeController.Year()); + current.month = static_cast(dateTimeController.Month()); + current.day = static_cast(dateTimeController.Day()); + + // Set today's date + lv_calendar_set_today_date(calendar, ¤t); + lv_calendar_set_showed_date(calendar, ¤t); +} + +bool Calendar::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + switch (event) { + case TouchEvents::SwipeLeft: { + if (current.month == 12) { + current.month = 1; + current.year++; + } else { + current.month++; + } + + lv_calendar_set_showed_date(calendar, ¤t); + return true; + } + case TouchEvents::SwipeRight: { + if (current.month == 1) { + current.month = 12; + current.year--; + } else { + current.month--; + } + + lv_calendar_set_showed_date(calendar, ¤t); + return true; + } + /* + case TouchEvents::SwipeUp: { + current.year++; + lv_calendar_set_showed_date(calendar, ¤t); + return true; + } + case TouchEvents::SwipeDown: { + current.year--; + lv_calendar_set_showed_date(calendar, ¤t); + return true; + } + */ + default: { + return false; + } + } +} + +Calendar::~Calendar() { + lv_obj_clean(lv_scr_act()); +} diff --git a/src/displayapp/screens/Calendar.h b/src/displayapp/screens/Calendar.h new file mode 100644 index 00000000..bbdc8322 --- /dev/null +++ b/src/displayapp/screens/Calendar.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2024 thnikk, Boteium, JustScott + + This file is part of InfiniTime. + + InfiniTime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + InfiniTime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#include "displayapp/apps/Apps.h" +#include "displayapp/Controllers.h" +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include + +#include "Symbols.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + } + + namespace Applications { + namespace Screens { + class Calendar : public Screen { + public: + Calendar(Controllers::DateTime& dateTimeController); + ~Calendar() override; + + private: + bool OnTouchEvent(TouchEvents event); + Controllers::DateTime& dateTimeController; + lv_obj_t* calendar; + lv_calendar_date_t current; + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Calendar; + static constexpr const char* icon = Screens::Symbols::calendar; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::Calendar(controllers.dateTimeController); + }; + }; + } +} diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index b0305d8f..eff3c58d 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -21,6 +21,7 @@ namespace Pinetime { static constexpr const char* paintbrush = "\xEF\x87\xBC"; static constexpr const char* paddle = "\xEF\x91\x9D"; static constexpr const char* map = "\xEF\x96\xa0"; + static constexpr const char* dove = "\xEF\x92\xBA"; static constexpr const char* phone = "\xEF\x82\x95"; static constexpr const char* phoneSlash = "\xEF\x8F\x9D"; static constexpr const char* volumMute = "\xEF\x9A\xA9"; @@ -41,8 +42,7 @@ namespace Pinetime { static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* calculator = "\xEF\x87\xAC"; static constexpr const char* backspace = "\xEF\x95\x9A"; - - + static constexpr const char* calendar = "\xEF\x81\xB3"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index a1ede6be..dbfaeff5 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -17,7 +17,8 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { } } -Timer::Timer(Controllers::Timer& timerController) : timer {timerController} { +Timer::Timer(Controllers::Timer& timerController, Controllers::MotorController& motorController) + : timer {timerController}, motorController {motorController} { 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); @@ -62,7 +63,9 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} { txtPlayPause = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0); - if (timer.IsRunning()) { + if (motorController.IsRinging()) { + SetTimerRinging(); + } else if (timer.IsRunning()) { SetTimerRunning(); } else { SetTimerStopped(); @@ -103,7 +106,19 @@ void Timer::UpdateMask() { } void Timer::Refresh() { - if (timer.IsRunning()) { + if (isRinging) { + auto secondsElapsed = std::chrono::duration_cast(timer.GetTimeRemaining()); + minuteCounter.SetValue(secondsElapsed.count() / 60); + secondCounter.SetValue(secondsElapsed.count() % 60); + // Stop buzzing after 10 seconds, but continue the counter + if (motorController.IsRinging() && secondsElapsed.count() > 10) { + motorController.StopRinging(); + } + // Reset timer after 1 minute + if (secondsElapsed.count() > 60) { + Reset(); + } + } else if (timer.IsRunning()) { auto secondsRemaining = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsRemaining.count() / 60); secondCounter.SetValue(secondsRemaining.count() % 60); @@ -123,16 +138,33 @@ void Timer::SetTimerRunning() { minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Pause"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } void Timer::SetTimerStopped() { + isRinging = false; minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); +} + +void Timer::SetTimerRinging() { + isRinging = true; + minuteCounter.HideControls(); + secondCounter.HideControls(); + lv_label_set_text_static(txtPlayPause, "Reset"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + if (ringTime == 0) { + ringTime = xTaskGetTickCount(); + } } void Timer::ToggleRunning() { - if (timer.IsRunning()) { + if (isRinging) { + motorController.StopRinging(); + Reset(); + } else if (timer.IsRunning()) { auto secondsRemaining = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsRemaining.count() / 60); secondCounter.SetValue(secondsRemaining.count() % 60); diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 409cae1c..62ae96a7 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -2,6 +2,7 @@ #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" +#include "components/motor/MotorController.h" #include "systemtask/SystemTask.h" #include "displayapp/LittleVgl.h" #include "displayapp/widgets/Counter.h" @@ -14,19 +15,21 @@ namespace Pinetime::Applications { namespace Screens { class Timer : public Screen { public: - Timer(Controllers::Timer& timerController); + Timer(Controllers::Timer& timerController, Controllers::MotorController& motorController); ~Timer() override; void Refresh() override; void Reset(); void ToggleRunning(); void ButtonPressed(); void MaskReset(); + void SetTimerRinging(); private: void SetTimerRunning(); void SetTimerStopped(); void UpdateMask(); Pinetime::Controllers::Timer& timer; + Pinetime::Controllers::MotorController& motorController; lv_obj_t* btnPlayPause; lv_obj_t* txtPlayPause; @@ -41,8 +44,10 @@ namespace Pinetime::Applications { Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76); bool buttonPressing = false; + bool isRinging = false; lv_coord_t maskPosition = 0; TickType_t pressTime = 0; + TickType_t ringTime = 0; }; } @@ -52,7 +57,7 @@ namespace Pinetime::Applications { static constexpr const char* icon = Screens::Symbols::hourGlass; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Timer(controllers.timer); + return new Screens::Timer(controllers.timer, controllers.motorController); }; }; } diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 4e29f15c..62d967f8 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -66,10 +66,6 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); - /*label_time_ampm = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(label_time_ampm, ""); - lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55);*/ - heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); @@ -115,16 +111,11 @@ void WatchFaceDigital::Refresh() { uint8_t second = dateTimeController.Seconds(); if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - /*char ampmChar[3] = "AM"; if (hour == 0) { hour = 12; - } else if (hour == 12) { - ampmChar[0] = 'P'; } else if (hour > 12) { hour = hour - 12; - ampmChar[0] = 'P'; } - lv_label_set_text(label_time_ampm, ampmChar);*/ lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); } else {