Combine reader activities under ReaderActivity

This commit is contained in:
Dave Allie 2025-12-17 23:16:57 +11:00
parent 83012b2d0d
commit a9b4d99ac4
No known key found for this signature in database
GPG Key ID: F2FDDB3AD8D0276F
9 changed files with 156 additions and 58 deletions

View File

@ -9,6 +9,8 @@
constexpr uint8_t STATE_FILE_VERSION = 1;
constexpr char STATE_FILE[] = "/sd/.crosspoint/state.bin";
CrossPointState CrossPointState::instance;
bool CrossPointState::saveToFile() const {
std::ofstream outputFile(STATE_FILE);
serialization::writePod(outputFile, STATE_FILE_VERSION);

View File

@ -3,11 +3,20 @@
#include <string>
class CrossPointState {
// Static instance
static CrossPointState instance;
public:
std::string openEpubPath;
~CrossPointState() = default;
// Get singleton instance
static CrossPointState& getInstance() { return instance; }
bool saveToFile() const;
bool loadFromFile();
};
// Helper macro to access settings
#define APP_STATE CrossPointState::getInstance()

View File

@ -0,0 +1,21 @@
#include "ActivityWithSubactivity.h"
void ActivityWithSubactivity::exitActivity() {
if (subActivity) {
subActivity->onExit();
subActivity.reset();
}
}
void ActivityWithSubactivity::enterNewActivity(Activity* activity) {
subActivity.reset(activity);
subActivity->onEnter();
}
void ActivityWithSubactivity::loop() {
if (subActivity) {
subActivity->loop();
}
}
void ActivityWithSubactivity::onExit() { exitActivity(); }

View File

@ -0,0 +1,17 @@
#pragma once
#include <memory>
#include "Activity.h"
class ActivityWithSubactivity : public Activity {
protected:
std::unique_ptr<Activity> subActivity = nullptr;
void exitActivity();
void enterNewActivity(Activity* activity);
public:
explicit ActivityWithSubactivity(GfxRenderer& renderer, InputManager& inputManager)
: Activity(renderer, inputManager) {}
void loop() override;
void onExit() override;
};

View File

@ -45,7 +45,7 @@ void HomeActivity::loop() {
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
if (selectorIndex == 0) {
onFileSelectionOpen();
onReaderOpen();
} else if (selectorIndex == 1) {
onSettingsOpen();
}

View File

@ -12,7 +12,7 @@ class HomeActivity final : public Activity {
SemaphoreHandle_t renderingMutex = nullptr;
int selectorIndex = 0;
bool updateRequired = false;
const std::function<void()> onFileSelectionOpen;
const std::function<void()> onReaderOpen;
const std::function<void()> onSettingsOpen;
static constexpr int menuItemCount = 2;
@ -22,9 +22,9 @@ class HomeActivity final : public Activity {
void render() const;
public:
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager,
const std::function<void()>& onFileSelectionOpen, const std::function<void()>& onSettingsOpen)
: Activity(renderer, inputManager), onFileSelectionOpen(onFileSelectionOpen), onSettingsOpen(onSettingsOpen) {}
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
const std::function<void()>& onSettingsOpen)
: Activity(renderer, inputManager), onReaderOpen(onReaderOpen), onSettingsOpen(onSettingsOpen) {}
void onEnter() override;
void onExit() override;
void loop() override;

View File

@ -0,0 +1,68 @@
#include "ReaderActivity.h"
#include <SD.h>
#include "CrossPointState.h"
#include "Epub.h"
#include "EpubReaderActivity.h"
#include "FileSelectionActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto epub = std::unique_ptr<Epub>(new Epub(path, "/.crosspoint"));
if (epub->load()) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
return nullptr;
}
void ReaderActivity::onSelectEpubFile(const std::string& path) {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
auto epub = loadEpub(path);
if (epub) {
APP_STATE.openEpubPath = path;
APP_STATE.saveToFile();
onGoToEpubReader(std::move(epub));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Failed to load epub", REGULAR,
EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
}
void ReaderActivity::onGoToFileSelection() {
exitActivity();
enterNewActivity(new FileSelectionActivity(
renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack));
}
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
exitActivity();
enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), [this] { onGoToFileSelection(); }));
}
void ReaderActivity::onEnter() {
if (initialEpubPath.empty()) {
onGoToFileSelection();
return;
}
auto epub = loadEpub(initialEpubPath);
if (!epub) {
onGoBack();
return;
}
onGoToEpubReader(std::move(epub));
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <memory>
#include "../ActivityWithSubactivity.h"
class Epub;
class ReaderActivity final : public ActivityWithSubactivity {
std::string initialEpubPath;
const std::function<void()> onGoBack;
static std::unique_ptr<Epub> loadEpub(const std::string& path);
void onSelectEpubFile(const std::string& path);
void onGoToFileSelection();
void onGoToEpubReader(std::unique_ptr<Epub> epub);
public:
explicit ReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::string initialEpubPath,
const std::function<void()>& onGoBack)
: ActivityWithSubactivity(renderer, inputManager),
initialEpubPath(std::move(initialEpubPath)),
onGoBack(onGoBack) {}
void onEnter() override;
};

View File

@ -19,8 +19,7 @@
#include "activities/boot_sleep/BootActivity.h"
#include "activities/boot_sleep/SleepActivity.h"
#include "activities/home/HomeActivity.h"
#include "activities/reader/EpubReaderActivity.h"
#include "activities/reader/FileSelectionActivity.h"
#include "activities/reader/ReaderActivity.h"
#include "activities/settings/SettingsActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
#include "config.h"
@ -43,7 +42,6 @@ EInkDisplay einkDisplay(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
InputManager inputManager;
GfxRenderer renderer(einkDisplay);
Activity* currentActivity;
CrossPointState appState;
// Fonts
EpdFont bookerlyFont(&bookerly_2b);
@ -67,21 +65,6 @@ constexpr unsigned long POWER_BUTTON_SLEEP_MS = 500;
// Auto-sleep timeout (10 minutes of inactivity)
constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000;
std::unique_ptr<Epub> loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto epub = std::unique_ptr<Epub>(new Epub(path, "/.crosspoint"));
if (epub->load()) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
return nullptr;
}
void exitActivity() {
if (currentActivity) {
currentActivity->onExit();
@ -151,30 +134,11 @@ void enterDeepSleep() {
}
void onGoHome();
void onGoToFileSelection();
void onSelectEpubFile(const std::string& path) {
void onGoToReader(const std::string& initialEpubPath) {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
auto epub = loadEpub(path);
if (epub) {
appState.openEpubPath = path;
appState.saveToFile();
exitActivity();
enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), onGoToFileSelection));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Failed to load epub", REGULAR,
EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
}
void onGoToFileSelection() {
exitActivity();
enterNewActivity(new FileSelectionActivity(renderer, inputManager, onSelectEpubFile, onGoHome));
enterNewActivity(new ReaderActivity(renderer, inputManager, initialEpubPath, onGoHome));
}
void onGoToReaderHome() { onGoToReader(std::string()); }
void onGoToSettings() {
exitActivity();
@ -183,7 +147,7 @@ void onGoToSettings() {
void onGoHome() {
exitActivity();
enterNewActivity(new HomeActivity(renderer, inputManager, onGoToFileSelection, onGoToSettings));
enterNewActivity(new HomeActivity(renderer, inputManager, onGoToReaderHome, onGoToSettings));
}
void setup() {
@ -216,20 +180,13 @@ void setup() {
SD.begin(SD_SPI_CS, SPI, SPI_FQ);
SETTINGS.loadFromFile();
appState.loadFromFile();
if (!appState.openEpubPath.empty()) {
auto epub = loadEpub(appState.openEpubPath);
if (epub) {
exitActivity();
enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), onGoHome));
// Ensure we're not still holding the power button before leaving setup
waitForPowerRelease();
return;
}
APP_STATE.loadFromFile();
if (APP_STATE.openEpubPath.empty()) {
onGoHome();
} else {
onGoToReader(APP_STATE.openEpubPath);
}
onGoHome();
// Ensure we're not still holding the power button before leaving setup
waitForPowerRelease();
}