Give activities names and log when entering and exiting them (#92)
## Summary * Give activities name and log when entering and exiting them * Clearer logs when attempting to debug, knowing where users are coming from/going to helps
This commit is contained in:
parent
246afae6ef
commit
77c655fcf5
@ -1,19 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <InputManager.h>
|
#include <InputManager.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class GfxRenderer;
|
class GfxRenderer;
|
||||||
|
|
||||||
class Activity {
|
class Activity {
|
||||||
protected:
|
protected:
|
||||||
|
std::string name;
|
||||||
GfxRenderer& renderer;
|
GfxRenderer& renderer;
|
||||||
InputManager& inputManager;
|
InputManager& inputManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Activity(GfxRenderer& renderer, InputManager& inputManager)
|
explicit Activity(std::string name, GfxRenderer& renderer, InputManager& inputManager)
|
||||||
: renderer(renderer), inputManager(inputManager) {}
|
: name(std::move(name)), renderer(renderer), inputManager(inputManager) {}
|
||||||
virtual ~Activity() = default;
|
virtual ~Activity() = default;
|
||||||
virtual void onEnter() {}
|
virtual void onEnter() { Serial.printf("[%lu] [ACT] Entering activity: %s\n", millis(), name.c_str()); }
|
||||||
virtual void onExit() {}
|
virtual void onExit() { Serial.printf("[%lu] [ACT] Exiting activity: %s\n", millis(), name.c_str()); }
|
||||||
virtual void loop() {}
|
virtual void loop() {}
|
||||||
virtual bool skipLoopDelay() { return false; }
|
virtual bool skipLoopDelay() { return false; }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,4 +18,7 @@ void ActivityWithSubactivity::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityWithSubactivity::onExit() { exitActivity(); }
|
void ActivityWithSubactivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
exitActivity();
|
||||||
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ class ActivityWithSubactivity : public Activity {
|
|||||||
void enterNewActivity(Activity* activity);
|
void enterNewActivity(Activity* activity);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ActivityWithSubactivity(GfxRenderer& renderer, InputManager& inputManager)
|
explicit ActivityWithSubactivity(std::string name, GfxRenderer& renderer, InputManager& inputManager)
|
||||||
: Activity(renderer, inputManager) {}
|
: Activity(std::move(name), renderer, inputManager) {}
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,8 @@
|
|||||||
#include "images/CrossLarge.h"
|
#include "images/CrossLarge.h"
|
||||||
|
|
||||||
void BootActivity::onEnter() {
|
void BootActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
class BootActivity final : public Activity {
|
class BootActivity final : public Activity {
|
||||||
public:
|
public:
|
||||||
explicit BootActivity(GfxRenderer& renderer, InputManager& inputManager) : Activity(renderer, inputManager) {}
|
explicit BootActivity(GfxRenderer& renderer, InputManager& inputManager) : Activity("Boot", renderer, inputManager) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "images/CrossLarge.h"
|
#include "images/CrossLarge.h"
|
||||||
|
|
||||||
void SleepActivity::onEnter() {
|
void SleepActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
renderPopup("Entering Sleep...");
|
renderPopup("Entering Sleep...");
|
||||||
|
|
||||||
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::CUSTOM) {
|
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::CUSTOM) {
|
||||||
@ -170,11 +171,16 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SleepActivity::renderCoverSleepScreen() const {
|
void SleepActivity::renderCoverSleepScreen() const {
|
||||||
|
if (APP_STATE.openEpubPath.empty()) {
|
||||||
|
return renderDefaultSleepScreen();
|
||||||
|
}
|
||||||
|
|
||||||
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
|
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
|
||||||
if (!lastEpub.load()) {
|
if (!lastEpub.load()) {
|
||||||
Serial.println("[SLP] Failed to load last epub");
|
Serial.println("[SLP] Failed to load last epub");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastEpub.generateCoverBmp()) {
|
if (!lastEpub.generateCoverBmp()) {
|
||||||
Serial.println("[SLP] Failed to generate cover bmp");
|
Serial.println("[SLP] Failed to generate cover bmp");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
|
|||||||
@ -5,7 +5,8 @@ class Bitmap;
|
|||||||
|
|
||||||
class SleepActivity final : public Activity {
|
class SleepActivity final : public Activity {
|
||||||
public:
|
public:
|
||||||
explicit SleepActivity(GfxRenderer& renderer, InputManager& inputManager) : Activity(renderer, inputManager) {}
|
explicit SleepActivity(GfxRenderer& renderer, InputManager& inputManager)
|
||||||
|
: Activity("Sleep", renderer, inputManager) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -15,6 +15,8 @@ void HomeActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HomeActivity::onEnter() {
|
void HomeActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
@ -31,6 +33,8 @@ void HomeActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HomeActivity::onExit() {
|
void HomeActivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
|
||||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class HomeActivity final : public Activity {
|
|||||||
public:
|
public:
|
||||||
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
|
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
|
||||||
const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen)
|
const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen)
|
||||||
: Activity(renderer, inputManager),
|
: Activity("Home", renderer, inputManager),
|
||||||
onReaderOpen(onReaderOpen),
|
onReaderOpen(onReaderOpen),
|
||||||
onSettingsOpen(onSettingsOpen),
|
onSettingsOpen(onSettingsOpen),
|
||||||
onFileTransferOpen(onFileTransferOpen) {}
|
onFileTransferOpen(onFileTransferOpen) {}
|
||||||
|
|||||||
@ -11,7 +11,8 @@ void CrossPointWebServerActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::onEnter() {
|
void CrossPointWebServerActivity::onEnter() {
|
||||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onEnter ==========\n", millis());
|
ActivityWithSubactivity::onEnter();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
@ -36,13 +37,13 @@ void CrossPointWebServerActivity::onEnter() {
|
|||||||
|
|
||||||
// Launch WiFi selection subactivity
|
// Launch WiFi selection subactivity
|
||||||
Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis());
|
||||||
wifiSelection.reset(new WifiSelectionActivity(renderer, inputManager,
|
enterNewActivity(new WifiSelectionActivity(renderer, inputManager,
|
||||||
[this](bool connected) { onWifiSelectionComplete(connected); }));
|
[this](const bool connected) { onWifiSelectionComplete(connected); }));
|
||||||
wifiSelection->onEnter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::onExit() {
|
void CrossPointWebServerActivity::onExit() {
|
||||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onExit START ==========\n", millis());
|
ActivityWithSubactivity::onExit();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
state = WebServerActivityState::SHUTTING_DOWN;
|
state = WebServerActivityState::SHUTTING_DOWN;
|
||||||
@ -50,14 +51,6 @@ void CrossPointWebServerActivity::onExit() {
|
|||||||
// Stop the web server first (before disconnecting WiFi)
|
// Stop the web server first (before disconnecting WiFi)
|
||||||
stopWebServer();
|
stopWebServer();
|
||||||
|
|
||||||
// Exit WiFi selection subactivity if still active
|
|
||||||
if (wifiSelection) {
|
|
||||||
Serial.printf("[%lu] [WEBACT] Exiting WifiSelectionActivity...\n", millis());
|
|
||||||
wifiSelection->onExit();
|
|
||||||
wifiSelection.reset();
|
|
||||||
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity exited\n", millis());
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
||||||
Serial.printf("[%lu] [WEBACT] Waiting 500ms for network stack to flush pending packets...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Waiting 500ms for network stack to flush pending packets...\n", millis());
|
||||||
delay(500);
|
delay(500);
|
||||||
@ -92,20 +85,17 @@ void CrossPointWebServerActivity::onExit() {
|
|||||||
Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis());
|
Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis());
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onExit COMPLETE ==========\n", millis());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::onWifiSelectionComplete(bool connected) {
|
void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) {
|
||||||
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected);
|
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected);
|
||||||
|
|
||||||
if (connected) {
|
if (connected) {
|
||||||
// Get connection info before exiting subactivity
|
// Get connection info before exiting subactivity
|
||||||
connectedIP = wifiSelection->getConnectedIP();
|
connectedIP = static_cast<WifiSelectionActivity*>(subActivity.get())->getConnectedIP();
|
||||||
connectedSSID = WiFi.SSID().c_str();
|
connectedSSID = WiFi.SSID().c_str();
|
||||||
|
|
||||||
// Exit the wifi selection subactivity
|
exitActivity();
|
||||||
wifiSelection->onExit();
|
|
||||||
wifiSelection.reset();
|
|
||||||
|
|
||||||
// Start the web server
|
// Start the web server
|
||||||
startWebServer();
|
startWebServer();
|
||||||
@ -150,20 +140,18 @@ void CrossPointWebServerActivity::stopWebServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::loop() {
|
void CrossPointWebServerActivity::loop() {
|
||||||
// Handle different states
|
if (subActivity) {
|
||||||
switch (state) {
|
// Forward loop to subactivity
|
||||||
case WebServerActivityState::WIFI_SELECTION:
|
subActivity->loop();
|
||||||
// Forward loop to WiFi selection subactivity
|
return;
|
||||||
if (wifiSelection) {
|
|
||||||
wifiSelection->loop();
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case WebServerActivityState::SERVER_RUNNING:
|
// Handle different states
|
||||||
|
if (state == WebServerActivityState::SERVER_RUNNING) {
|
||||||
// Handle web server requests - call handleClient multiple times per loop
|
// Handle web server requests - call handleClient multiple times per loop
|
||||||
// to improve responsiveness and upload throughput
|
// to improve responsiveness and upload throughput
|
||||||
if (webServer && webServer->isRunning()) {
|
if (webServer && webServer->isRunning()) {
|
||||||
unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime;
|
const unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime;
|
||||||
|
|
||||||
// Log if there's a significant gap between handleClient calls (>100ms)
|
// Log if there's a significant gap between handleClient calls (>100ms)
|
||||||
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
||||||
@ -186,11 +174,6 @@ void CrossPointWebServerActivity::loop() {
|
|||||||
onGoBack();
|
onGoBack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case WebServerActivityState::SHUTTING_DOWN:
|
|
||||||
// Do nothing - waiting for cleanup
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "../Activity.h"
|
#include "../Activity.h"
|
||||||
#include "WifiSelectionActivity.h"
|
#include "WifiSelectionActivity.h"
|
||||||
|
#include "activities/ActivityWithSubactivity.h"
|
||||||
#include "server/CrossPointWebServer.h"
|
#include "server/CrossPointWebServer.h"
|
||||||
|
|
||||||
// Web server activity states
|
// Web server activity states
|
||||||
@ -26,16 +27,13 @@ enum class WebServerActivityState {
|
|||||||
* - Handles client requests in its loop() function
|
* - Handles client requests in its loop() function
|
||||||
* - Cleans up the server and shuts down WiFi on exit
|
* - Cleans up the server and shuts down WiFi on exit
|
||||||
*/
|
*/
|
||||||
class CrossPointWebServerActivity final : public Activity {
|
class CrossPointWebServerActivity final : public ActivityWithSubactivity {
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
bool updateRequired = false;
|
bool updateRequired = false;
|
||||||
WebServerActivityState state = WebServerActivityState::WIFI_SELECTION;
|
WebServerActivityState state = WebServerActivityState::WIFI_SELECTION;
|
||||||
const std::function<void()> onGoBack;
|
const std::function<void()> onGoBack;
|
||||||
|
|
||||||
// WiFi selection subactivity
|
|
||||||
std::unique_ptr<WifiSelectionActivity> wifiSelection;
|
|
||||||
|
|
||||||
// Web server - owned by this activity
|
// Web server - owned by this activity
|
||||||
std::unique_ptr<CrossPointWebServer> webServer;
|
std::unique_ptr<CrossPointWebServer> webServer;
|
||||||
|
|
||||||
@ -58,7 +56,7 @@ class CrossPointWebServerActivity final : public Activity {
|
|||||||
public:
|
public:
|
||||||
explicit CrossPointWebServerActivity(GfxRenderer& renderer, InputManager& inputManager,
|
explicit CrossPointWebServerActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
const std::function<void()>& onGoBack)
|
const std::function<void()>& onGoBack)
|
||||||
: Activity(renderer, inputManager), onGoBack(onGoBack) {}
|
: ActivityWithSubactivity("CrossPointWebServer", renderer, inputManager), onGoBack(onGoBack) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@ -14,6 +14,8 @@ void WifiSelectionActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::onEnter() {
|
void WifiSelectionActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
// Load saved WiFi credentials
|
// Load saved WiFi credentials
|
||||||
@ -47,7 +49,8 @@ void WifiSelectionActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::onExit() {
|
void WifiSelectionActivity::onExit() {
|
||||||
Serial.printf("[%lu] [WIFI] ========== WifiSelectionActivity onExit START ==========\n", millis());
|
Activity::onExit();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Stop any ongoing WiFi scan
|
// Stop any ongoing WiFi scan
|
||||||
@ -78,7 +81,6 @@ void WifiSelectionActivity::onExit() {
|
|||||||
Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis());
|
Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis());
|
||||||
|
|
||||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
Serial.printf("[%lu] [WIFI] ========== WifiSelectionActivity onExit COMPLETE ==========\n", millis());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::startWifiScan() {
|
void WifiSelectionActivity::startWifiScan() {
|
||||||
|
|||||||
@ -98,7 +98,7 @@ class WifiSelectionActivity final : public Activity {
|
|||||||
public:
|
public:
|
||||||
explicit WifiSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
|
explicit WifiSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
const std::function<void(bool connected)>& onComplete)
|
const std::function<void(bool connected)>& onComplete)
|
||||||
: Activity(renderer, inputManager), onComplete(onComplete) {}
|
: Activity("WifiSelection", renderer, inputManager), onComplete(onComplete) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@ -26,6 +26,8 @@ void EpubReaderActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderActivity::onEnter() {
|
void EpubReaderActivity::onEnter() {
|
||||||
|
ActivityWithSubactivity::onEnter();
|
||||||
|
|
||||||
if (!epub) {
|
if (!epub) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -61,6 +63,8 @@ void EpubReaderActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderActivity::onExit() {
|
void EpubReaderActivity::onExit() {
|
||||||
|
ActivityWithSubactivity::onExit();
|
||||||
|
|
||||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
@ -75,8 +79,8 @@ void EpubReaderActivity::onExit() {
|
|||||||
|
|
||||||
void EpubReaderActivity::loop() {
|
void EpubReaderActivity::loop() {
|
||||||
// Pass input responsibility to sub activity if exists
|
// Pass input responsibility to sub activity if exists
|
||||||
if (subAcitivity) {
|
if (subActivity) {
|
||||||
subAcitivity->loop();
|
subActivity->loop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,11 +88,11 @@ void EpubReaderActivity::loop() {
|
|||||||
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||||
// Don't start activity transition while rendering
|
// Don't start activity transition while rendering
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
subAcitivity.reset(new EpubReaderChapterSelectionActivity(
|
exitActivity();
|
||||||
|
enterNewActivity(new EpubReaderChapterSelectionActivity(
|
||||||
this->renderer, this->inputManager, epub, currentSpineIndex,
|
this->renderer, this->inputManager, epub, currentSpineIndex,
|
||||||
[this] {
|
[this] {
|
||||||
subAcitivity->onExit();
|
exitActivity();
|
||||||
subAcitivity.reset();
|
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
},
|
},
|
||||||
[this](const int newSpineIndex) {
|
[this](const int newSpineIndex) {
|
||||||
@ -97,11 +101,9 @@ void EpubReaderActivity::loop() {
|
|||||||
nextPageNumber = 0;
|
nextPageNumber = 0;
|
||||||
section.reset();
|
section.reset();
|
||||||
}
|
}
|
||||||
subAcitivity->onExit();
|
exitActivity();
|
||||||
subAcitivity.reset();
|
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
}));
|
}));
|
||||||
subAcitivity->onEnter();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,8 +332,8 @@ void EpubReaderActivity::renderStatusBar() const {
|
|||||||
constexpr auto textY = 776;
|
constexpr auto textY = 776;
|
||||||
|
|
||||||
// Calculate progress in book
|
// Calculate progress in book
|
||||||
float sectionChapterProg = static_cast<float>(section->currentPage) / section->pageCount;
|
const float sectionChapterProg = static_cast<float>(section->currentPage) / section->pageCount;
|
||||||
uint8_t bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg);
|
const uint8_t bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg);
|
||||||
|
|
||||||
// Right aligned text for progress counter
|
// Right aligned text for progress counter
|
||||||
const std::string progress = std::to_string(section->currentPage + 1) + "/" + std::to_string(section->pageCount) +
|
const std::string progress = std::to_string(section->currentPage + 1) + "/" + std::to_string(section->pageCount) +
|
||||||
|
|||||||
@ -5,14 +5,13 @@
|
|||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
|
|
||||||
#include "../Activity.h"
|
#include "activities/ActivityWithSubactivity.h"
|
||||||
|
|
||||||
class EpubReaderActivity final : public Activity {
|
class EpubReaderActivity final : public ActivityWithSubactivity {
|
||||||
std::shared_ptr<Epub> epub;
|
std::shared_ptr<Epub> epub;
|
||||||
std::unique_ptr<Section> section = nullptr;
|
std::unique_ptr<Section> section = nullptr;
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
std::unique_ptr<Activity> subAcitivity = nullptr;
|
|
||||||
int currentSpineIndex = 0;
|
int currentSpineIndex = 0;
|
||||||
int nextPageNumber = 0;
|
int nextPageNumber = 0;
|
||||||
int pagesUntilFullRefresh = 0;
|
int pagesUntilFullRefresh = 0;
|
||||||
@ -28,7 +27,7 @@ class EpubReaderActivity final : public Activity {
|
|||||||
public:
|
public:
|
||||||
explicit EpubReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
|
explicit EpubReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
|
||||||
const std::function<void()>& onGoBack)
|
const std::function<void()>& onGoBack)
|
||||||
: Activity(renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
|
: ActivityWithSubactivity("EpubReader", renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@ -16,6 +16,8 @@ void EpubReaderChapterSelectionActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderChapterSelectionActivity::onEnter() {
|
void EpubReaderChapterSelectionActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
if (!epub) {
|
if (!epub) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -34,6 +36,8 @@ void EpubReaderChapterSelectionActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderChapterSelectionActivity::onExit() {
|
void EpubReaderChapterSelectionActivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
|
||||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class EpubReaderChapterSelectionActivity final : public Activity {
|
|||||||
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
|
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
|
||||||
const std::function<void()>& onGoBack,
|
const std::function<void()>& onGoBack,
|
||||||
const std::function<void(int newSpineIndex)>& onSelectSpineIndex)
|
const std::function<void(int newSpineIndex)>& onSelectSpineIndex)
|
||||||
: Activity(renderer, inputManager),
|
: Activity("EpubReaderChapterSelection", renderer, inputManager),
|
||||||
epub(epub),
|
epub(epub),
|
||||||
currentSpineIndex(currentSpineIndex),
|
currentSpineIndex(currentSpineIndex),
|
||||||
onGoBack(onGoBack),
|
onGoBack(onGoBack),
|
||||||
|
|||||||
@ -48,6 +48,8 @@ void FileSelectionActivity::loadFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FileSelectionActivity::onEnter() {
|
void FileSelectionActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
basepath = "/";
|
basepath = "/";
|
||||||
@ -66,6 +68,8 @@ void FileSelectionActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FileSelectionActivity::onExit() {
|
void FileSelectionActivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
|
||||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class FileSelectionActivity final : public Activity {
|
|||||||
explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
|
explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
const std::function<void(const std::string&)>& onSelect,
|
const std::function<void(const std::string&)>& onSelect,
|
||||||
const std::function<void()>& onGoHome)
|
const std::function<void()>& onGoHome)
|
||||||
: Activity(renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {}
|
: Activity("FileSelection", renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@ -50,6 +50,8 @@ void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReaderActivity::onEnter() {
|
void ReaderActivity::onEnter() {
|
||||||
|
ActivityWithSubactivity::onEnter();
|
||||||
|
|
||||||
if (initialEpubPath.empty()) {
|
if (initialEpubPath.empty()) {
|
||||||
onGoToFileSelection();
|
onGoToFileSelection();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class ReaderActivity final : public ActivityWithSubactivity {
|
|||||||
public:
|
public:
|
||||||
explicit ReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::string initialEpubPath,
|
explicit ReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::string initialEpubPath,
|
||||||
const std::function<void()>& onGoBack)
|
const std::function<void()>& onGoBack)
|
||||||
: ActivityWithSubactivity(renderer, inputManager),
|
: ActivityWithSubactivity("Reader", renderer, inputManager),
|
||||||
initialEpubPath(std::move(initialEpubPath)),
|
initialEpubPath(std::move(initialEpubPath)),
|
||||||
onGoBack(onGoBack) {}
|
onGoBack(onGoBack) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
|
|||||||
@ -21,6 +21,8 @@ void SettingsActivity::taskTrampoline(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SettingsActivity::onEnter() {
|
void SettingsActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
// Reset selection to first item
|
// Reset selection to first item
|
||||||
@ -38,6 +40,8 @@ void SettingsActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SettingsActivity::onExit() {
|
void SettingsActivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
|
||||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
@ -76,7 +80,7 @@ void SettingsActivity::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsActivity::toggleCurrentSetting() {
|
void SettingsActivity::toggleCurrentSetting() const {
|
||||||
// Validate index
|
// Validate index
|
||||||
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
|
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -32,11 +32,11 @@ class SettingsActivity final : public Activity {
|
|||||||
static void taskTrampoline(void* param);
|
static void taskTrampoline(void* param);
|
||||||
[[noreturn]] void displayTaskLoop();
|
[[noreturn]] void displayTaskLoop();
|
||||||
void render() const;
|
void render() const;
|
||||||
void toggleCurrentSetting();
|
void toggleCurrentSetting() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SettingsActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoHome)
|
explicit SettingsActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoHome)
|
||||||
: Activity(renderer, inputManager), onGoHome(onGoHome) {}
|
: Activity("Settings", renderer, inputManager), onGoHome(onGoHome) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
void FullScreenMessageActivity::onEnter() {
|
void FullScreenMessageActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||||
const auto top = (GfxRenderer::getScreenHeight() - height) / 2;
|
const auto top = (GfxRenderer::getScreenHeight() - height) / 2;
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,9 @@ class FullScreenMessageActivity final : public Activity {
|
|||||||
explicit FullScreenMessageActivity(GfxRenderer& renderer, InputManager& inputManager, std::string text,
|
explicit FullScreenMessageActivity(GfxRenderer& renderer, InputManager& inputManager, std::string text,
|
||||||
const EpdFontStyle style = REGULAR,
|
const EpdFontStyle style = REGULAR,
|
||||||
const EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH)
|
const EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH)
|
||||||
: Activity(renderer, inputManager), text(std::move(text)), style(style), refreshMode(refreshMode) {}
|
: Activity("FullScreenMessage", renderer, inputManager),
|
||||||
|
text(std::move(text)),
|
||||||
|
style(style),
|
||||||
|
refreshMode(refreshMode) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,11 +12,6 @@ const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = {
|
|||||||
const char* const KeyboardEntryActivity::keyboardShift[NUM_ROWS] = {"~!@#$%^&*()_+", "QWERTYUIOP{}|", "ASDFGHJKL:\"",
|
const char* const KeyboardEntryActivity::keyboardShift[NUM_ROWS] = {"~!@#$%^&*()_+", "QWERTYUIOP{}|", "ASDFGHJKL:\"",
|
||||||
"ZXCVBNM<>?", "^ _____<OK"};
|
"ZXCVBNM<>?", "^ _____<OK"};
|
||||||
|
|
||||||
KeyboardEntryActivity::KeyboardEntryActivity(GfxRenderer& renderer, InputManager& inputManager,
|
|
||||||
const std::string& title, const std::string& initialText, size_t maxLength,
|
|
||||||
bool isPassword)
|
|
||||||
: Activity(renderer, inputManager), title(title), text(initialText), maxLength(maxLength), isPassword(isPassword) {}
|
|
||||||
|
|
||||||
void KeyboardEntryActivity::setText(const std::string& newText) {
|
void KeyboardEntryActivity::setText(const std::string& newText) {
|
||||||
text = newText;
|
text = newText;
|
||||||
if (maxLength > 0 && text.length() > maxLength) {
|
if (maxLength > 0 && text.length() > maxLength) {
|
||||||
@ -37,15 +32,13 @@ void KeyboardEntryActivity::reset(const std::string& newTitle, const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardEntryActivity::onEnter() {
|
void KeyboardEntryActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
// Reset state when entering the activity
|
// Reset state when entering the activity
|
||||||
complete = false;
|
complete = false;
|
||||||
cancelled = false;
|
cancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardEntryActivity::onExit() {
|
|
||||||
// Clean up if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardEntryActivity::loop() {
|
void KeyboardEntryActivity::loop() {
|
||||||
handleInput();
|
handleInput();
|
||||||
render(10);
|
render(10);
|
||||||
|
|||||||
@ -34,7 +34,12 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
* @param isPassword If true, display asterisks instead of actual characters
|
* @param isPassword If true, display asterisks instead of actual characters
|
||||||
*/
|
*/
|
||||||
KeyboardEntryActivity(GfxRenderer& renderer, InputManager& inputManager, const std::string& title = "Enter Text",
|
KeyboardEntryActivity(GfxRenderer& renderer, InputManager& inputManager, const std::string& title = "Enter Text",
|
||||||
const std::string& initialText = "", size_t maxLength = 0, bool isPassword = false);
|
const std::string& initialText = "", const size_t maxLength = 0, const bool isPassword = false)
|
||||||
|
: Activity("KeyboardEntry", renderer, inputManager),
|
||||||
|
title(title),
|
||||||
|
text(initialText),
|
||||||
|
maxLength(maxLength),
|
||||||
|
isPassword(isPassword) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle button input. Call this in your main loop.
|
* Handle button input. Call this in your main loop.
|
||||||
@ -85,7 +90,6 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
|
|
||||||
// Activity overrides
|
// Activity overrides
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user