diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a97a0158b..b96c32ed39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -675,6 +675,7 @@ set(INCLUDE_FILES buttonhandler/ButtonHandler.h touchhandler/TouchHandler.h utility/Math.h + utility/Persistent.h ) include_directories( diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp index 00298eca9a..993e85cc02 100644 --- a/src/displayapp/screens/Paddle.cpp +++ b/src/displayapp/screens/Paddle.cpp @@ -6,7 +6,12 @@ using namespace Pinetime::Applications::Screens; -Paddle::Paddle(Pinetime::Components::LittleVgl& lvgl) : lvgl {lvgl} { +Paddle::Paddle(Pinetime::Components::LittleVgl& lvgl, + Pinetime::Controllers::FS& fs) + : Persistent(fs), + lvgl {lvgl} { + LoadPersistentState(); + background = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_size(background, LV_HOR_RES + 1, LV_VER_RES); lv_obj_set_pos(background, -1, 0); @@ -34,6 +39,8 @@ Paddle::Paddle(Pinetime::Components::LittleVgl& lvgl) : lvgl {lvgl} { } Paddle::~Paddle() { + SavePersistentState(); + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); } @@ -66,17 +73,17 @@ void Paddle::Refresh() { if (ballX >= -ballSize / 4) { if (ballY <= (paddlePos + 30 - ballSize / 4) && ballY >= (paddlePos - 30 - ballSize + ballSize / 4)) { dx *= -1; - score++; + persistent_state.score++; } } // checks if it has gone behind the paddle else if (ballX <= -ballSize * 2) { ballX = (LV_HOR_RES - ballSize) / 2; ballY = (LV_VER_RES - ballSize) / 2; - score = 0; + persistent_state.score = 0; } } - lv_label_set_text_fmt(points, "%04d", score); + lv_label_set_text_fmt(points, "%04d", persistent_state.score); } bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents /*event*/) { diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h index 586cccf4cf..f0effcece1 100644 --- a/src/displayapp/screens/Paddle.h +++ b/src/displayapp/screens/Paddle.h @@ -2,22 +2,32 @@ #include #include +#include "components/fs/FS.h" #include "displayapp/screens/Screen.h" #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" +#include "utility/Persistent.h" + +using namespace Pinetime::Utility; namespace Pinetime { + namespace Controllers { + class FS; + } namespace Components { class LittleVgl; } namespace Applications { namespace Screens { + struct PaddleState { + uint16_t score; + }; - class Paddle : public Screen { + class Paddle : public Screen, public Persistent { public: - Paddle(Pinetime::Components::LittleVgl& lvgl); + Paddle(Pinetime::Components::LittleVgl& lvgl, Pinetime::Controllers::FS& fs); ~Paddle() override; void Refresh() override; @@ -25,6 +35,15 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(uint16_t x, uint16_t y) override; + protected: + char* GetPersistencePath() override { + return "persistent/paddle"; + } + + uint32_t GetDataVersion() override { + return 0; + } + private: Pinetime::Components::LittleVgl& lvgl; @@ -38,8 +57,6 @@ namespace Pinetime { int8_t dx = 2; // Velocity of the ball in the x_coordinate int8_t dy = 3; // Velocity of the ball in the y_coordinate - uint16_t score = 0; - lv_obj_t* points; lv_obj_t* paddle; lv_obj_t* ball; @@ -55,7 +72,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::paddle; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Paddle(controllers.lvgl); + return new Screens::Paddle(controllers.lvgl, controllers.filesystem); }; }; } diff --git a/src/utility/Persistent.h b/src/utility/Persistent.h new file mode 100644 index 0000000000..94f5d9fb4f --- /dev/null +++ b/src/utility/Persistent.h @@ -0,0 +1,61 @@ +#pragma once + +#include "components/fs/FS.h" + +using namespace Pinetime::Controllers; + +namespace Pinetime { + namespace Utility { + template + class Persistent { + public: + Persistent(Pinetime::Controllers::FS& fs); + + protected: + Pinetime::Controllers::FS& fs; + + virtual char* GetPersistencePath() = 0; + virtual uint32_t GetDataVersion() = 0; + + void LoadPersistentState(); + void SavePersistentState(); + + struct PersistentState : T { + uint32_t version; + }; + + PersistentState persistent_state {}; + }; + + template + Persistent::Persistent(Pinetime::Controllers::FS& fs) : fs {fs} { + persistent_state.version = this->GetDataVersion(); + } + + template + void Persistent::LoadPersistentState() { + Persistent::PersistentState buffer; + lfs_file_t file; + + if (fs.FileOpen(&file, this->GetPersistencePath(), LFS_O_RDONLY) != LFS_ERR_OK) { + return; + } + fs.FileRead(&file, reinterpret_cast(&buffer), sizeof(persistent_state)); + fs.FileClose(&file); + if (buffer.version == this->GetDataVersion()) { + persistent_state = buffer; + } + } + + template + void Persistent::SavePersistentState() { + lfs_file_t file; + + if (fs.FileOpen(&file, this->GetPersistencePath(), LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + return; + } + fs.FileWrite(&file, reinterpret_cast(&persistent_state), sizeof(persistent_state)); + fs.FileClose(&file); + } + } +} \ No newline at end of file