Save Frame Visibility Actions (#10576)
Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
This commit is contained in:
co-authored by
GitHub
HarukiToreda
parent
5154e81d0b
commit
a212d2e84f
@@ -50,6 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "MessageStore.h"
|
#include "MessageStore.h"
|
||||||
#include "RadioLibInterface.h"
|
#include "RadioLibInterface.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
@@ -655,6 +656,10 @@ void Screen::setup()
|
|||||||
brightness = uiconfig.screen_brightness;
|
brightness = uiconfig.screen_brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore which frames the user has hidden (persisted across reboots).
|
||||||
|
// Must happen before the first setFrames().
|
||||||
|
loadFrameVisibility();
|
||||||
|
|
||||||
// Detect OLED subtype (if supported by board variant)
|
// Detect OLED subtype (if supported by board variant)
|
||||||
#ifdef AutoOLEDWire_h
|
#ifdef AutoOLEDWire_h
|
||||||
if (isAUTOOled)
|
if (isAUTOOled)
|
||||||
@@ -1416,6 +1421,9 @@ void Screen::toggleFrameVisibility(const std::string &frameName)
|
|||||||
if (frameName == "chirpy") {
|
if (frameName == "chirpy") {
|
||||||
hiddenFrames.chirpy = !hiddenFrames.chirpy;
|
hiddenFrames.chirpy = !hiddenFrames.chirpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the new visibility state so it survives a reboot.
|
||||||
|
saveFrameVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Screen::isFrameHidden(const std::string &frameName) const
|
bool Screen::isFrameHidden(const std::string &frameName) const
|
||||||
@@ -1454,6 +1462,167 @@ bool Screen::isFrameHidden(const std::string &frameName) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Frame visibility persistence
|
||||||
|
//
|
||||||
|
// The set of hideable frames varies by build (USE_EINK, HAS_GPS, ...), so we
|
||||||
|
// serialize to a fixed bitmask where each frame name owns a permanent bit
|
||||||
|
// position. Bits for frames that don't exist in the current build are simply
|
||||||
|
// left untouched, which keeps the saved file portable across firmware variants.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static const char *frameVisibilityFileName = "/prefs/framevis";
|
||||||
|
constexpr uint32_t FRAMEVIS_MAGIC = 0x53495646; // "FVIS" little-endian
|
||||||
|
constexpr uint8_t FRAMEVIS_VERSION = 1;
|
||||||
|
|
||||||
|
// Permanent bit assignments. Never renumber these; only append new ones.
|
||||||
|
enum FrameVisBit : uint8_t {
|
||||||
|
FVBIT_TEXT_MESSAGE = 0,
|
||||||
|
FVBIT_WAYPOINT = 1,
|
||||||
|
FVBIT_WIFI = 2,
|
||||||
|
FVBIT_SYSTEM = 3,
|
||||||
|
FVBIT_HOME = 4,
|
||||||
|
FVBIT_CLOCK = 5,
|
||||||
|
FVBIT_NODELIST_NODES = 6,
|
||||||
|
FVBIT_NODELIST_LOCATION = 7,
|
||||||
|
FVBIT_NODELIST_LASTHEARD = 8,
|
||||||
|
FVBIT_NODELIST_HOPSIGNAL = 9,
|
||||||
|
FVBIT_NODELIST_DISTANCE = 10,
|
||||||
|
FVBIT_NODELIST_BEARINGS = 11,
|
||||||
|
FVBIT_GPS = 12,
|
||||||
|
FVBIT_LORA = 13,
|
||||||
|
FVBIT_SHOW_FAVORITES = 14,
|
||||||
|
FVBIT_CHIRPY = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((packed)) FrameVisFile {
|
||||||
|
uint32_t magic;
|
||||||
|
uint8_t version;
|
||||||
|
uint32_t mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void setBit(uint32_t &mask, uint8_t bit, bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
mask |= (1UL << bit);
|
||||||
|
else
|
||||||
|
mask &= ~(1UL << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool getBit(uint32_t mask, uint8_t bit)
|
||||||
|
{
|
||||||
|
return (mask & (1UL << bit)) != 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
uint32_t Screen::packHiddenFrames() const
|
||||||
|
{
|
||||||
|
uint32_t mask = 0;
|
||||||
|
setBit(mask, FVBIT_TEXT_MESSAGE, hiddenFrames.textMessage);
|
||||||
|
setBit(mask, FVBIT_WAYPOINT, hiddenFrames.waypoint);
|
||||||
|
setBit(mask, FVBIT_WIFI, hiddenFrames.wifi);
|
||||||
|
setBit(mask, FVBIT_SYSTEM, hiddenFrames.system);
|
||||||
|
setBit(mask, FVBIT_HOME, hiddenFrames.home);
|
||||||
|
setBit(mask, FVBIT_CLOCK, hiddenFrames.clock);
|
||||||
|
#ifndef USE_EINK
|
||||||
|
setBit(mask, FVBIT_NODELIST_NODES, hiddenFrames.nodelist_nodes);
|
||||||
|
setBit(mask, FVBIT_NODELIST_LOCATION, hiddenFrames.nodelist_location);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EINK
|
||||||
|
setBit(mask, FVBIT_NODELIST_LASTHEARD, hiddenFrames.nodelist_lastheard);
|
||||||
|
setBit(mask, FVBIT_NODELIST_HOPSIGNAL, hiddenFrames.nodelist_hopsignal);
|
||||||
|
setBit(mask, FVBIT_NODELIST_DISTANCE, hiddenFrames.nodelist_distance);
|
||||||
|
#endif
|
||||||
|
#if HAS_GPS
|
||||||
|
#ifdef USE_EINK
|
||||||
|
setBit(mask, FVBIT_NODELIST_BEARINGS, hiddenFrames.nodelist_bearings);
|
||||||
|
#endif
|
||||||
|
setBit(mask, FVBIT_GPS, hiddenFrames.gps);
|
||||||
|
#endif
|
||||||
|
setBit(mask, FVBIT_LORA, hiddenFrames.lora);
|
||||||
|
setBit(mask, FVBIT_SHOW_FAVORITES, hiddenFrames.show_favorites);
|
||||||
|
setBit(mask, FVBIT_CHIRPY, hiddenFrames.chirpy);
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::applyHiddenFramesMask(uint32_t mask)
|
||||||
|
{
|
||||||
|
hiddenFrames.textMessage = getBit(mask, FVBIT_TEXT_MESSAGE);
|
||||||
|
hiddenFrames.waypoint = getBit(mask, FVBIT_WAYPOINT);
|
||||||
|
hiddenFrames.wifi = getBit(mask, FVBIT_WIFI);
|
||||||
|
hiddenFrames.system = getBit(mask, FVBIT_SYSTEM);
|
||||||
|
hiddenFrames.home = getBit(mask, FVBIT_HOME);
|
||||||
|
hiddenFrames.clock = getBit(mask, FVBIT_CLOCK);
|
||||||
|
#ifndef USE_EINK
|
||||||
|
hiddenFrames.nodelist_nodes = getBit(mask, FVBIT_NODELIST_NODES);
|
||||||
|
hiddenFrames.nodelist_location = getBit(mask, FVBIT_NODELIST_LOCATION);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EINK
|
||||||
|
hiddenFrames.nodelist_lastheard = getBit(mask, FVBIT_NODELIST_LASTHEARD);
|
||||||
|
hiddenFrames.nodelist_hopsignal = getBit(mask, FVBIT_NODELIST_HOPSIGNAL);
|
||||||
|
hiddenFrames.nodelist_distance = getBit(mask, FVBIT_NODELIST_DISTANCE);
|
||||||
|
#endif
|
||||||
|
#if HAS_GPS
|
||||||
|
#ifdef USE_EINK
|
||||||
|
hiddenFrames.nodelist_bearings = getBit(mask, FVBIT_NODELIST_BEARINGS);
|
||||||
|
#endif
|
||||||
|
hiddenFrames.gps = getBit(mask, FVBIT_GPS);
|
||||||
|
#endif
|
||||||
|
hiddenFrames.lora = getBit(mask, FVBIT_LORA);
|
||||||
|
hiddenFrames.show_favorites = getBit(mask, FVBIT_SHOW_FAVORITES);
|
||||||
|
hiddenFrames.chirpy = getBit(mask, FVBIT_CHIRPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::loadFrameVisibility()
|
||||||
|
{
|
||||||
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
|
auto file = FSCom.open(frameVisibilityFileName, FILE_O_READ);
|
||||||
|
if (file) {
|
||||||
|
FrameVisFile data{};
|
||||||
|
bool ok = file.read((uint8_t *)&data, sizeof(data)) == sizeof(data) && data.magic == FRAMEVIS_MAGIC &&
|
||||||
|
data.version == FRAMEVIS_VERSION;
|
||||||
|
file.close();
|
||||||
|
spiLock->unlock();
|
||||||
|
if (ok) {
|
||||||
|
applyHiddenFramesMask(data.mask);
|
||||||
|
LOG_INFO("Loaded frame visibility (mask 0x%08x)", data.mask);
|
||||||
|
} else {
|
||||||
|
LOG_WARN("Frame visibility file invalid, keeping defaults");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spiLock->unlock();
|
||||||
|
LOG_DEBUG("No saved frame visibility, using defaults");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::saveFrameVisibility()
|
||||||
|
{
|
||||||
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
|
FSCom.mkdir("/prefs");
|
||||||
|
if (FSCom.exists(frameVisibilityFileName))
|
||||||
|
FSCom.remove(frameVisibilityFileName);
|
||||||
|
|
||||||
|
auto file = FSCom.open(frameVisibilityFileName, FILE_O_WRITE);
|
||||||
|
if (file) {
|
||||||
|
FrameVisFile data{};
|
||||||
|
data.magic = FRAMEVIS_MAGIC;
|
||||||
|
data.version = FRAMEVIS_VERSION;
|
||||||
|
data.mask = packHiddenFrames();
|
||||||
|
file.write((uint8_t *)&data, sizeof(data));
|
||||||
|
file.flush();
|
||||||
|
file.close();
|
||||||
|
LOG_INFO("Saved frame visibility (mask 0x%08x)", data.mask);
|
||||||
|
} else {
|
||||||
|
LOG_WARN("Failed to open %s for writing", frameVisibilityFileName);
|
||||||
|
}
|
||||||
|
spiLock->unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Screen::handleStartFirmwareUpdateScreen()
|
void Screen::handleStartFirmwareUpdateScreen()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Show firmware screen");
|
LOG_DEBUG("Show firmware screen");
|
||||||
|
|||||||
@@ -623,6 +623,11 @@ class Screen : public concurrency::OSThread
|
|||||||
void toggleFrameVisibility(const std::string &frameName);
|
void toggleFrameVisibility(const std::string &frameName);
|
||||||
bool isFrameHidden(const std::string &frameName) const;
|
bool isFrameHidden(const std::string &frameName) const;
|
||||||
|
|
||||||
|
// Persist / restore which frames are hidden, across reboots.
|
||||||
|
// Stored as a single uint32 bitmask in /prefs (see Screen.cpp for the format).
|
||||||
|
void loadFrameVisibility();
|
||||||
|
void saveFrameVisibility();
|
||||||
|
|
||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
/// Draw an image to remain on E-Ink display after screen off
|
/// Draw an image to remain on E-Ink display after screen off
|
||||||
void setScreensaverFrames(FrameCallback einkScreensaver = NULL);
|
void setScreensaverFrames(FrameCallback einkScreensaver = NULL);
|
||||||
@@ -738,6 +743,11 @@ class Screen : public concurrency::OSThread
|
|||||||
bool chirpy = true;
|
bool chirpy = true;
|
||||||
} hiddenFrames;
|
} hiddenFrames;
|
||||||
|
|
||||||
|
// Convert hiddenFrames to a uint32 bitmask. Bit positions are fixed per
|
||||||
|
// frame name (see Screen.cpp).
|
||||||
|
uint32_t packHiddenFrames() const;
|
||||||
|
void applyHiddenFramesMask(uint32_t mask);
|
||||||
|
|
||||||
/// Try to start drawing ASAP
|
/// Try to start drawing ASAP
|
||||||
void setFastFramerate();
|
void setFastFramerate();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user