Add setting to allow for cover sleep screen
This commit is contained in:
parent
c50257c9da
commit
a8350d46fd
@ -23,7 +23,7 @@ bool CrossPointSettings::saveToFile() const {
|
||||
std::ofstream outputFile(SETTINGS_FILE);
|
||||
serialization::writePod(outputFile, SETTINGS_FILE_VERSION);
|
||||
serialization::writePod(outputFile, SETTINGS_COUNT);
|
||||
serialization::writePod(outputFile, whiteSleepScreen);
|
||||
serialization::writePod(outputFile, sleepScreen);
|
||||
serialization::writePod(outputFile, extraParagraphSpacing);
|
||||
serialization::writePod(outputFile, shortPwrBtn);
|
||||
outputFile.close();
|
||||
@ -54,7 +54,7 @@ bool CrossPointSettings::loadFromFile() {
|
||||
// load settings that exist
|
||||
uint8_t settingsRead = 0;
|
||||
do {
|
||||
serialization::readPod(inputFile, whiteSleepScreen);
|
||||
serialization::readPod(inputFile, sleepScreen);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, extraParagraphSpacing);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
|
||||
@ -15,8 +15,11 @@ class CrossPointSettings {
|
||||
CrossPointSettings(const CrossPointSettings&) = delete;
|
||||
CrossPointSettings& operator=(const CrossPointSettings&) = delete;
|
||||
|
||||
// Should match with SettingsActivity text
|
||||
enum SLEEP_SCREEN_MODE { DARK = 0, LIGHT = 1, CUSTOM = 2, COVER = 3 };
|
||||
|
||||
// Sleep screen settings
|
||||
uint8_t whiteSleepScreen = 0;
|
||||
uint8_t sleepScreen = DARK;
|
||||
// Text rendering settings
|
||||
uint8_t extraParagraphSpacing = 1;
|
||||
// Duration of the power button press
|
||||
|
||||
@ -1,16 +1,45 @@
|
||||
#include "SleepActivity.h"
|
||||
|
||||
#include <Epub.h>
|
||||
#include <GfxRenderer.h>
|
||||
#include <SD.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "CrossPointState.h"
|
||||
#include "config.h"
|
||||
#include "images/CrossLarge.h"
|
||||
|
||||
void SleepActivity::onEnter() {
|
||||
renderPopup("Entering Sleep...");
|
||||
|
||||
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::CUSTOM) {
|
||||
return renderCustomSleepScreen();
|
||||
}
|
||||
|
||||
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::COVER) {
|
||||
return renderCoverSleepScreen();
|
||||
}
|
||||
|
||||
renderDefaultSleepScreen();
|
||||
}
|
||||
|
||||
void SleepActivity::renderPopup(const char* message) const {
|
||||
const int textWidth = renderer.getTextWidth(READER_FONT_ID, message);
|
||||
constexpr int margin = 20;
|
||||
const int x = (renderer.getScreenWidth() - textWidth - margin * 2) / 2;
|
||||
constexpr int y = 117;
|
||||
const int w = textWidth + margin * 2;
|
||||
const int h = renderer.getLineHeight(READER_FONT_ID) + margin * 2;
|
||||
// renderer.clearScreen();
|
||||
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
|
||||
renderer.drawText(READER_FONT_ID, x + margin, y + margin, message);
|
||||
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
void SleepActivity::renderCustomSleepScreen() const {
|
||||
// Check if we have a /sleep directory
|
||||
auto dir = SD.open("/sleep");
|
||||
if (dir && dir.isDirectory()) {
|
||||
@ -28,31 +57,31 @@ void SleepActivity::onEnter() {
|
||||
}
|
||||
|
||||
if (filename.substr(filename.length() - 4) != ".bmp") {
|
||||
Serial.printf("[%lu] [Slp] Skipping non-.bmp file name: %s\n", millis(), file.name());
|
||||
Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), file.name());
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
|
||||
Serial.printf("[%lu] [Slp] Skipping invalid BMP file: %s\n", millis(), file.name());
|
||||
Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), file.name());
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
files.emplace_back(filename);
|
||||
file.close();
|
||||
}
|
||||
int numFiles = files.size();
|
||||
const auto numFiles = files.size();
|
||||
if (numFiles > 0) {
|
||||
// Generate a random number between 1 and numFiles
|
||||
int randomFileIndex = random(numFiles);
|
||||
auto filename = "/sleep/" + files[randomFileIndex];
|
||||
const auto randomFileIndex = random(numFiles);
|
||||
const auto filename = "/sleep/" + files[randomFileIndex];
|
||||
auto file = SD.open(filename.c_str());
|
||||
if (file) {
|
||||
Serial.printf("[%lu] [Slp] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
|
||||
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
|
||||
delay(100);
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
renderCustomSleepScreen(bitmap);
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
dir.close();
|
||||
return;
|
||||
}
|
||||
@ -67,8 +96,8 @@ void SleepActivity::onEnter() {
|
||||
if (file) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
Serial.printf("[%lu] [Slp] Loading: /sleep.bmp\n", millis());
|
||||
renderCustomSleepScreen(bitmap);
|
||||
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -76,41 +105,27 @@ void SleepActivity::onEnter() {
|
||||
renderDefaultSleepScreen();
|
||||
}
|
||||
|
||||
void SleepActivity::renderPopup(const char* message) const {
|
||||
const int textWidth = renderer.getTextWidth(READER_FONT_ID, message);
|
||||
constexpr int margin = 20;
|
||||
const int x = (GfxRenderer::getScreenWidth() - textWidth - margin * 2) / 2;
|
||||
constexpr int y = 117;
|
||||
const int w = textWidth + margin * 2;
|
||||
const int h = renderer.getLineHeight(READER_FONT_ID) + margin * 2;
|
||||
// renderer.clearScreen();
|
||||
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
|
||||
renderer.drawText(READER_FONT_ID, x + margin, y + margin, message);
|
||||
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
void SleepActivity::renderDefaultSleepScreen() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
|
||||
renderer.clearScreen();
|
||||
renderer.drawImage(CrossLarge, (pageWidth - 128) / 2, (pageHeight - 128) / 2, 128, 128);
|
||||
renderer.drawCenteredText(UI_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "SLEEPING");
|
||||
|
||||
// Apply white screen if enabled in settings
|
||||
if (!SETTINGS.whiteSleepScreen) {
|
||||
// Make sleep screen dark unless light is selected in settings
|
||||
if (SETTINGS.sleepScreen != CrossPointSettings::SLEEP_SCREEN_MODE::LIGHT) {
|
||||
renderer.invertScreen();
|
||||
}
|
||||
|
||||
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
||||
}
|
||||
|
||||
void SleepActivity::renderCustomSleepScreen(const Bitmap& bitmap) const {
|
||||
void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
||||
int x, y;
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
|
||||
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
|
||||
// image will scale, make sure placement is right
|
||||
@ -153,3 +168,26 @@ void SleepActivity::renderCustomSleepScreen(const Bitmap& bitmap) const {
|
||||
renderer.setRenderMode(GfxRenderer::BW);
|
||||
}
|
||||
}
|
||||
|
||||
void SleepActivity::renderCoverSleepScreen() const {
|
||||
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
|
||||
if (!lastEpub.load()) {
|
||||
Serial.println("[SLP] Failed to load last epub");
|
||||
return renderDefaultSleepScreen();
|
||||
}
|
||||
if (!lastEpub.generateCoverBmp()) {
|
||||
Serial.println("[SLP] Failed to generate cover bmp");
|
||||
return renderDefaultSleepScreen();
|
||||
}
|
||||
|
||||
auto file = SD.open(lastEpub.getCoverBmpPath().c_str(), FILE_READ);
|
||||
if (file) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
renderDefaultSleepScreen();
|
||||
}
|
||||
|
||||
@ -9,7 +9,9 @@ class SleepActivity final : public Activity {
|
||||
void onEnter() override;
|
||||
|
||||
private:
|
||||
void renderDefaultSleepScreen() const;
|
||||
void renderCustomSleepScreen(const Bitmap& bitmap) const;
|
||||
void renderPopup(const char* message) const;
|
||||
void renderDefaultSleepScreen() const;
|
||||
void renderCustomSleepScreen() const;
|
||||
void renderCoverSleepScreen() const;
|
||||
void renderBitmapSleepScreen(const Bitmap& bitmap) const;
|
||||
};
|
||||
|
||||
@ -6,11 +6,14 @@
|
||||
#include "config.h"
|
||||
|
||||
// Define the static settings list
|
||||
|
||||
const SettingInfo SettingsActivity::settingsList[settingsCount] = {
|
||||
{"White Sleep Screen", SettingType::TOGGLE, &CrossPointSettings::whiteSleepScreen},
|
||||
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing},
|
||||
{"Short Power Button Click", SettingType::TOGGLE, &CrossPointSettings::shortPwrBtn}};
|
||||
namespace {
|
||||
constexpr int settingsCount = 3;
|
||||
const SettingInfo settingsList[settingsCount] = {
|
||||
// Should match with SLEEP_SCREEN_MODE
|
||||
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
||||
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing, {}},
|
||||
{"Short Power Button Click", SettingType::TOGGLE, &CrossPointSettings::shortPwrBtn, {}}};
|
||||
} // namespace
|
||||
|
||||
void SettingsActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<SettingsActivity*>(param);
|
||||
@ -81,15 +84,18 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
|
||||
const auto& setting = settingsList[selectedSettingIndex];
|
||||
|
||||
if (setting.type == SettingType::TOGGLE && setting.valuePtr != nullptr) {
|
||||
// Toggle the boolean value using the member pointer
|
||||
const bool currentValue = SETTINGS.*(setting.valuePtr);
|
||||
SETTINGS.*(setting.valuePtr) = !currentValue;
|
||||
} else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) {
|
||||
const uint8_t currentValue = SETTINGS.*(setting.valuePtr);
|
||||
SETTINGS.*(setting.valuePtr) = (currentValue + 1) % static_cast<uint8_t>(setting.enumValues.size());
|
||||
} else {
|
||||
// Only toggle if it's a toggle type and has a value pointer
|
||||
if (setting.type != SettingType::TOGGLE || setting.valuePtr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle the boolean value using the member pointer
|
||||
bool currentValue = SETTINGS.*(setting.valuePtr);
|
||||
SETTINGS.*(setting.valuePtr) = !currentValue;
|
||||
|
||||
// Save settings when they change
|
||||
SETTINGS.saveToFile();
|
||||
}
|
||||
@ -129,8 +135,13 @@ void SettingsActivity::render() const {
|
||||
|
||||
// Draw value based on setting type
|
||||
if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) {
|
||||
bool value = SETTINGS.*(settingsList[i].valuePtr);
|
||||
const bool value = SETTINGS.*(settingsList[i].valuePtr);
|
||||
renderer.drawText(UI_FONT_ID, pageWidth - 80, settingY, value ? "ON" : "OFF");
|
||||
} else if (settingsList[i].type == SettingType::ENUM && settingsList[i].valuePtr != nullptr) {
|
||||
const uint8_t value = SETTINGS.*(settingsList[i].valuePtr);
|
||||
auto valueText = settingsList[i].enumValues[value];
|
||||
const auto width = renderer.getTextWidth(UI_FONT_ID, valueText.c_str());
|
||||
renderer.drawText(UI_FONT_ID, pageWidth - 50 - width, settingY, valueText.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,13 +12,14 @@
|
||||
|
||||
class CrossPointSettings;
|
||||
|
||||
enum class SettingType { TOGGLE };
|
||||
enum class SettingType { TOGGLE, ENUM };
|
||||
|
||||
// Structure to hold setting information
|
||||
struct SettingInfo {
|
||||
const char* name; // Display name of the setting
|
||||
SettingType type; // Type of setting
|
||||
uint8_t CrossPointSettings::* valuePtr; // Pointer to member in CrossPointSettings (for TOGGLE)
|
||||
uint8_t CrossPointSettings::* valuePtr; // Pointer to member in CrossPointSettings (for TOGGLE/ENUM)
|
||||
std::vector<std::string> enumValues;
|
||||
};
|
||||
|
||||
class SettingsActivity final : public Activity {
|
||||
@ -28,10 +29,6 @@ class SettingsActivity final : public Activity {
|
||||
int selectedSettingIndex = 0; // Currently selected setting
|
||||
const std::function<void()> onGoHome;
|
||||
|
||||
// Static settings list
|
||||
static constexpr int settingsCount = 3; // Number of settings
|
||||
static const SettingInfo settingsList[settingsCount];
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user