Merge pull request #23 from jpirnay/feat-bmpviewer
feat: Amend back button handling, add "use as sleep screen" feature
This commit is contained in:
@@ -442,5 +442,7 @@ STR_UPTIME: "Uptime"
|
||||
STR_CHARGING: "Charging"
|
||||
STR_GATHERING_DATA: "Gathering data..."
|
||||
STR_READING: "Reading..."
|
||||
STR_SET_SLEEP_SCREEN: "Set Sleep"
|
||||
STR_SLEEP_SCREEN_SET: "Sleep screen updated!"
|
||||
STR_WEATHER_MOON_INFO: "Moon"
|
||||
STR_WEATHER_SUN_INFO: "Sun"
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <SdFat.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
#define SDCard SDCardManager::getInstance()
|
||||
|
||||
@@ -138,6 +139,35 @@ bool HalStorage::openFileForWrite(const char* moduleName, const String& path, Ha
|
||||
|
||||
bool HalStorage::removeDir(const char* path) { HAL_STORAGE_WRAPPED_CALL(removeDir, path); }
|
||||
|
||||
bool HalStorage::copyFile(const char* moduleName, const std::string& srcPath, const char* dstPath) {
|
||||
HalFile src, dst;
|
||||
if (!openFileForRead(moduleName, srcPath, src)) return false;
|
||||
if (!openFileForWrite(moduleName, dstPath, dst)) {
|
||||
src.close();
|
||||
return false;
|
||||
}
|
||||
constexpr size_t BUF_SIZE = 4096;
|
||||
auto* buf = new (std::nothrow) uint8_t[BUF_SIZE];
|
||||
if (!buf) {
|
||||
dst.close();
|
||||
src.close();
|
||||
return false;
|
||||
}
|
||||
bool ok = true;
|
||||
while (src.available()) {
|
||||
const auto bytesRead = src.read(buf, BUF_SIZE);
|
||||
if (bytesRead <= 0) break;
|
||||
if (dst.write(buf, bytesRead) != static_cast<size_t>(bytesRead)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] buf;
|
||||
dst.close();
|
||||
src.close();
|
||||
return ok;
|
||||
}
|
||||
|
||||
// HalFile implementation
|
||||
// Allow doing file operations while ensuring thread safety via HalStorage's mutex.
|
||||
// Please keep the list below in sync with the HalFile.h header
|
||||
|
||||
@@ -44,6 +44,7 @@ class HalStorage {
|
||||
bool openFileForWrite(const char* moduleName, const std::string& path, HalFile& file);
|
||||
bool openFileForWrite(const char* moduleName, const String& path, HalFile& file);
|
||||
bool removeDir(const char* path);
|
||||
bool copyFile(const char* moduleName, const std::string& srcPath, const char* dstPath);
|
||||
|
||||
uint64_t sdTotalBytes() const;
|
||||
uint64_t sdUsedBytes();
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
#include <HalStorage.h>
|
||||
#include <I18n.h>
|
||||
|
||||
#include "../reader/ReaderUtils.h"
|
||||
#include "CrossPointSettings.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
namespace {
|
||||
constexpr const char* SLEEP_BMP_PATH = "/sleep.bmp";
|
||||
} // namespace
|
||||
|
||||
BmpViewerActivity::BmpViewerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string path)
|
||||
: Activity("BmpViewer", renderer, mappedInput), filePath(std::move(path)) {}
|
||||
|
||||
@@ -49,7 +55,7 @@ void BmpViewerActivity::onEnter() {
|
||||
}
|
||||
|
||||
// 4. Prepare Rendering
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", tr(STR_SET_SLEEP_SCREEN));
|
||||
GUI.fillPopupProgress(renderer, popupRect, 50);
|
||||
|
||||
renderer.clearScreen();
|
||||
@@ -89,12 +95,44 @@ void BmpViewerActivity::onExit() {
|
||||
renderer.displayBuffer(HalDisplay::FULL_REFRESH);
|
||||
}
|
||||
|
||||
void BmpViewerActivity::setAsSleepScreen() {
|
||||
// Only copy if the source isn't already /sleep.bmp
|
||||
if (filePath != SLEEP_BMP_PATH) {
|
||||
if (!Storage.copyFile("BMP", filePath, SLEEP_BMP_PATH)) {
|
||||
LOG_ERR("BMP", "Failed to copy %s to %s", filePath.c_str(), SLEEP_BMP_PATH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Switch sleep screen mode to CUSTOM so the copied image is used
|
||||
SETTINGS.sleepScreen = CrossPointSettings::SLEEP_SCREEN_MODE::CUSTOM;
|
||||
SETTINGS.saveToFile();
|
||||
LOG_INF("BMP", "Set %s as sleep screen", filePath.c_str());
|
||||
|
||||
GUI.drawPopup(renderer, tr(STR_SLEEP_SCREEN_SET));
|
||||
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
||||
}
|
||||
|
||||
void BmpViewerActivity::loop() {
|
||||
// Keep CPU awake/polling so 1st click works
|
||||
Activity::loop();
|
||||
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
// Long press BACK (1s+) goes to home screen
|
||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= ReaderUtils::GO_HOME_MS) {
|
||||
onGoHome();
|
||||
return;
|
||||
}
|
||||
|
||||
// Short press BACK returns to the calling activity
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back) &&
|
||||
mappedInput.getHeldTime() < ReaderUtils::GO_HOME_MS) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Next/Right button: set this image as the sleep screen
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Right)) {
|
||||
setAsSleepScreen();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,5 @@ class BmpViewerActivity final : public Activity {
|
||||
|
||||
private:
|
||||
std::string filePath;
|
||||
void setAsSleepScreen();
|
||||
};
|
||||
Reference in New Issue
Block a user