Merge pull request #254 from jpirnay/feat-quick-resume

feat: Add quick resume (idea from #2064/#2089)
This commit is contained in:
jpirnay
2026-05-22 14:17:48 +02:00
committed by GitHub
41 changed files with 328 additions and 39 deletions
+2 -2
View File
@@ -351,8 +351,8 @@ void ActivityManager::returnFromChild() {
}
}
void ActivityManager::goToSleep() {
replaceActivity(std::make_unique<SleepActivity>(renderer, mappedInput));
void ActivityManager::goToSleep(bool fromTimeout) {
replaceActivity(std::make_unique<SleepActivity>(renderer, mappedInput, fromTimeout));
loop(); // Important: sleep screen must be rendered immediately, the caller will go to sleep right after this returns
}
+2 -1
View File
@@ -124,7 +124,8 @@ class ActivityManager {
void goToBrowser();
void goToReader(std::string path);
void goToKOReaderSync();
void goToSleep();
// fromTimeout=true marks this as an auto-sleep (used to gate Quick Resume on Timeout).
void goToSleep(bool fromTimeout = false);
void goToBoot();
void goToFullScreenMessage(std::string message, EpdFontFamily::Style style = EpdFontFamily::REGULAR);
void goToWeather();
@@ -24,6 +24,7 @@
#include "components/UITheme.h"
#include "fontIds.h"
#include "images/Logo120.h"
#include "images/MoonIcon.h"
namespace {
@@ -353,6 +354,18 @@ size_t pickSleepImageIndex(size_t numFiles) {
void SleepActivity::onEnter() {
Activity::onEnter();
RenderLock lock(*this);
// Quick Resume: paint a moon icon over the current page and keep the framebuffer
// intact for the next wake. Applies always when the user picked Quick Resume as
// sleep screen, or only on timeout sleeps when "Quick Resume on Timeout" is on.
const bool renderQuickResume =
SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::QUICK_RESUME ||
(fromTimeout &&
SETTINGS.quickResumeSleepScreen == CrossPointSettings::QUICK_RESUME_SLEEP_SCREEN::QUICK_RESUME_AFTER_TIMEOUT);
if (renderQuickResume) {
return renderLastScreenSleepScreen();
}
// For OVERLAY mode the popup is suppressed so the frame buffer (reader page) stays intact
if (SETTINGS.sleepScreen != CrossPointSettings::SLEEP_SCREEN_MODE::OVERLAY) {
GUI.drawPopup(renderer, tr(STR_ENTERING_SLEEP));
@@ -804,6 +817,15 @@ void SleepActivity::renderBlankSleepScreen() const {
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
}
void SleepActivity::renderLastScreenSleepScreen() const {
// Keep whatever is currently in the framebuffer (the reader page) and overlay a small moon
// icon to signal sleep. main.cpp persists the framebuffer to SD so the next wake can restore
// it before the boot screen would otherwise paint.
const auto pageHeight = renderer.getScreenHeight();
renderer.drawImage(MoonIcon, 0, pageHeight - MOONICON_HEIGHT, MOONICON_WIDTH, MOONICON_HEIGHT);
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
}
void SleepActivity::renderOverlaySleepScreen() const {
// Overlay pictures always use portrait orientation regardless of the reader's orientation preference.
const auto savedOrientation = renderer.getOrientation();
+6 -2
View File
@@ -16,8 +16,8 @@ struct BookOverlayInfo {
class SleepActivity final : public Activity {
public:
explicit SleepActivity(GfxRenderer& renderer, MappedInputManager& mappedInput)
: Activity("Sleep", renderer, mappedInput) {}
explicit SleepActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, bool fromTimeout = false)
: Activity("Sleep", renderer, mappedInput), fromTimeout(fromTimeout) {}
void onEnter() override;
private:
@@ -28,5 +28,9 @@ class SleepActivity final : public Activity {
bool topAlignForCoverFit = false) const;
void renderBlankSleepScreen() const;
void renderOverlaySleepScreen() const;
// Quick Resume: leaves the framebuffer (reader page) intact and overlays a small moon icon.
void renderLastScreenSleepScreen() const;
BookOverlayInfo getBookOverlayInfo(const std::string& bookPath) const;
const bool fromTimeout = false;
};
@@ -286,6 +286,7 @@ void SettingsActivity::toggleCurrentSetting() {
: FontSelectionActivity::Target::EPUB;
startActivityForResult(std::make_unique<FontSelectionActivity>(renderer, mappedInput, target),
[this](const ActivityResult&) {
CrossPointSettings::normalizeDependentSettings(SETTINGS);
SETTINGS.saveToFile();
needsHalfRefresh = true;
});
@@ -294,6 +295,7 @@ void SettingsActivity::toggleCurrentSetting() {
if (setting.type == SettingType::ACTION) {
auto resultHandler = [this](const ActivityResult& result) {
CrossPointSettings::normalizeDependentSettings(SETTINGS);
SETTINGS.saveToFile();
needsHalfRefresh = true;
const auto* menuResult = std::get_if<MenuResult>(&result.data);
@@ -301,6 +303,7 @@ void SettingsActivity::toggleCurrentSetting() {
auto activity = createActivityForAction(static_cast<SettingAction>(menuResult->action), renderer, mappedInput);
if (activity) {
startActivityForResult(std::move(activity), [this](const ActivityResult&) {
CrossPointSettings::normalizeDependentSettings(SETTINGS);
SETTINGS.saveToFile();
needsHalfRefresh = true;
});
@@ -323,6 +326,7 @@ void SettingsActivity::toggleCurrentSetting() {
}
setting.toggleValue();
CrossPointSettings::normalizeDependentSettings(SETTINGS);
SETTINGS.saveToFile();
}