From 2040e088e7b036e192c6ba52eb05f11e0f8406c3 Mon Sep 17 00:00:00 2001 From: Will Morrow Date: Wed, 14 Jan 2026 05:05:08 -0500 Subject: [PATCH] Ensure new custom sleep image every time (#300) When picking a random sleep image from a set of custom images, compare the randomly chosen index against a cached value in settings. If the value matches, use the next image (rolling over if it's the last image). Cache the chosen image index to settings in either case. ## Summary Implements a tweak on the custom sleep image feature that ensures that the user gets a new image every time the device goes to sleep. This change adds a new setting (perhaps there's a better place to cache this?) that stores the most recently used file index. During picking the random image index, we compare this against the random index and choose the next one (modulo the number of image files) if it matches, ensuring we get a new image. ## Additional Context As mentioned, I used settings to cache this value since it is a persisted store, perhaps that's overkill. Open to suggestions on if there's a better way. --- src/CrossPointState.cpp | 10 ++++++++-- src/CrossPointState.h | 1 + src/activities/boot_sleep/SleepActivity.cpp | 8 +++++++- src/main.cpp | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/CrossPointState.cpp b/src/CrossPointState.cpp index 31cb2ac..91aa253 100644 --- a/src/CrossPointState.cpp +++ b/src/CrossPointState.cpp @@ -5,7 +5,7 @@ #include namespace { -constexpr uint8_t STATE_FILE_VERSION = 1; +constexpr uint8_t STATE_FILE_VERSION = 2; constexpr char STATE_FILE[] = "/.crosspoint/state.bin"; } // namespace @@ -19,6 +19,7 @@ bool CrossPointState::saveToFile() const { serialization::writePod(outputFile, STATE_FILE_VERSION); serialization::writeString(outputFile, openEpubPath); + serialization::writePod(outputFile, lastSleepImage); outputFile.close(); return true; } @@ -31,13 +32,18 @@ bool CrossPointState::loadFromFile() { uint8_t version; serialization::readPod(inputFile, version); - if (version != STATE_FILE_VERSION) { + if (version > STATE_FILE_VERSION) { Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version); inputFile.close(); return false; } serialization::readString(inputFile, openEpubPath); + if (version >= 2) { + serialization::readPod(inputFile, lastSleepImage); + } else { + lastSleepImage = 0; + } inputFile.close(); return true; diff --git a/src/CrossPointState.h b/src/CrossPointState.h index f060a0c..87ce4e9 100644 --- a/src/CrossPointState.h +++ b/src/CrossPointState.h @@ -8,6 +8,7 @@ class CrossPointState { public: std::string openEpubPath; + uint8_t lastSleepImage; ~CrossPointState() = default; // Get singleton instance diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index 3305a16..0d3eab0 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -80,7 +80,13 @@ void SleepActivity::renderCustomSleepScreen() const { const auto numFiles = files.size(); if (numFiles > 0) { // Generate a random number between 1 and numFiles - const auto randomFileIndex = random(numFiles); + auto randomFileIndex = random(numFiles); + // If we picked the same image as last time, reroll + while (numFiles > 1 && randomFileIndex == APP_STATE.lastSleepImage) { + randomFileIndex = random(numFiles); + } + APP_STATE.lastSleepImage = randomFileIndex; + APP_STATE.saveToFile(); const auto filename = "/sleep/" + files[randomFileIndex]; FsFile file; if (SdMan.openFileForRead("SLP", filename, file)) { diff --git a/src/main.cpp b/src/main.cpp index 5261df3..34e7376 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -303,6 +303,7 @@ void setup() { // Clear app state to avoid getting into a boot loop if the epub doesn't load const auto path = APP_STATE.openEpubPath; APP_STATE.openEpubPath = ""; + APP_STATE.lastSleepImage = 0; APP_STATE.saveToFile(); onGoToReader(path); }