Fixed accidental regressions caused by commit f0dc218 and minor bug fixes
This commit is contained in:
@@ -72,11 +72,6 @@
|
||||
|
||||
/* -------------------------------------------------------------------------------------- */
|
||||
|
||||
// SD-backed settings persistence (defined in main.cpp for T-Deck Pro)
|
||||
#if defined(LilyGo_TDeck_Pro) && defined(HAS_SDCARD)
|
||||
extern void backupSettingsToSD();
|
||||
#endif
|
||||
|
||||
#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS
|
||||
#define REQ_TYPE_KEEP_ALIVE 0x02
|
||||
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
||||
@@ -174,12 +169,7 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
void savePrefs() {
|
||||
_store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon);
|
||||
#if defined(LilyGo_TDeck_Pro) && defined(HAS_SDCARD)
|
||||
backupSettingsToSD();
|
||||
#endif
|
||||
}
|
||||
void savePrefs() { _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); }
|
||||
void saveChannels() {
|
||||
_store->saveChannels(this);
|
||||
#if defined(LilyGo_TDeck_Pro) && defined(HAS_SDCARD)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "TextReaderScreen.h"
|
||||
#include "ContactsScreen.h"
|
||||
#include "ChannelScreen.h"
|
||||
#include "SettingsScreen.h"
|
||||
extern SPIClass displaySpi; // From GxEPDDisplay.cpp, shared SPI bus
|
||||
|
||||
TCA8418Keyboard keyboard(I2C_ADDR_KEYBOARD, &Wire);
|
||||
@@ -512,6 +513,23 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// First-boot onboarding detection
|
||||
// Check if node name is still the default hex prefix (first 4 bytes of pub key)
|
||||
// If so, launch onboarding wizard to set name and radio preset
|
||||
// ---------------------------------------------------------------------------
|
||||
#if defined(LilyGo_TDeck_Pro)
|
||||
{
|
||||
char defaultName[10];
|
||||
mesh::Utils::toHex(defaultName, the_mesh.self_id.pub_key, 4);
|
||||
NodePrefs* prefs = the_mesh.getNodePrefs();
|
||||
if (strcmp(prefs->node_name, defaultName) == 0) {
|
||||
MESH_DEBUG_PRINTLN("setup() - Default node name detected, launching onboarding");
|
||||
ui_task.gotoOnboarding();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// GPS duty cycle — honour saved pref, default to enabled on first boot
|
||||
#if HAS_GPS
|
||||
{
|
||||
@@ -787,20 +805,28 @@ void handleKeyboardInput() {
|
||||
return;
|
||||
}
|
||||
|
||||
// C key: allow entering compose mode from reader
|
||||
if (key == 'c' || key == 'C') {
|
||||
composeDM = false;
|
||||
composeDMContactIdx = -1;
|
||||
composeMode = true;
|
||||
composeBuffer[0] = '\0';
|
||||
composePos = 0;
|
||||
Serial.printf("Entering compose mode from reader, channel %d\n", composeChannelIdx);
|
||||
drawComposeScreen();
|
||||
lastComposeRefresh = millis();
|
||||
// All other keys pass through to the reader screen
|
||||
ui_task.injectKey(key);
|
||||
return;
|
||||
}
|
||||
|
||||
// *** SETTINGS MODE ***
|
||||
if (ui_task.isOnSettingsScreen()) {
|
||||
SettingsScreen* settings = (SettingsScreen*)ui_task.getSettingsScreen();
|
||||
|
||||
// Q key: exit settings (when not editing)
|
||||
if (!settings->isEditing() && (key == 'q' || key == 'Q')) {
|
||||
if (settings->hasRadioChanges()) {
|
||||
// Let settings show "apply changes?" confirm dialog
|
||||
ui_task.injectKey(key);
|
||||
} else {
|
||||
Serial.println("Exiting settings");
|
||||
ui_task.gotoHomeScreen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// All other keys pass through to the reader screen
|
||||
|
||||
// All other keys → settings screen via injectKey
|
||||
ui_task.injectKey(key);
|
||||
return;
|
||||
}
|
||||
@@ -809,36 +835,9 @@ void handleKeyboardInput() {
|
||||
switch (key) {
|
||||
case 'c':
|
||||
case 'C':
|
||||
// Enter compose mode - DM if on contacts screen, channel otherwise
|
||||
if (ui_task.isOnContactsScreen()) {
|
||||
ContactsScreen* cs = (ContactsScreen*)ui_task.getContactsScreen();
|
||||
int idx = cs->getSelectedContactIdx();
|
||||
uint8_t ctype = cs->getSelectedContactType();
|
||||
if (idx >= 0 && ctype == ADV_TYPE_CHAT) {
|
||||
composeDM = true;
|
||||
composeDMContactIdx = idx;
|
||||
cs->getSelectedContactName(composeDMName, sizeof(composeDMName));
|
||||
composeMode = true;
|
||||
composeBuffer[0] = '\0';
|
||||
composePos = 0;
|
||||
Serial.printf("Entering DM compose to %s (idx %d)\n", composeDMName, idx);
|
||||
drawComposeScreen();
|
||||
lastComposeRefresh = millis();
|
||||
}
|
||||
} else {
|
||||
composeDM = false;
|
||||
composeDMContactIdx = -1;
|
||||
composeMode = true;
|
||||
composeBuffer[0] = '\0';
|
||||
composePos = 0;
|
||||
// If on channel screen, sync compose channel with viewed channel
|
||||
if (ui_task.isOnChannelScreen()) {
|
||||
composeChannelIdx = ui_task.getChannelScreenViewIdx();
|
||||
}
|
||||
Serial.printf("Entering compose mode, channel %d\n", composeChannelIdx);
|
||||
drawComposeScreen();
|
||||
lastComposeRefresh = millis();
|
||||
}
|
||||
// Open contacts list
|
||||
Serial.println("Opening contacts");
|
||||
ui_task.gotoContactsScreen();
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
@@ -848,20 +847,24 @@ void handleKeyboardInput() {
|
||||
ui_task.gotoChannelScreen();
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
// Open text reader
|
||||
case 'e':
|
||||
case 'E':
|
||||
// Open text reader (ebooks)
|
||||
Serial.println("Opening text reader");
|
||||
ui_task.gotoTextReader();
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
// Open contacts list
|
||||
Serial.println("Opening contacts");
|
||||
ui_task.gotoContactsScreen();
|
||||
case 's':
|
||||
case 'S':
|
||||
// Open settings (from home), or navigate down on channel/contacts
|
||||
if (ui_task.isOnChannelScreen() || ui_task.isOnContactsScreen()) {
|
||||
ui_task.injectKey('s'); // Pass directly for channel/contacts scrolling
|
||||
} else {
|
||||
Serial.println("Opening settings");
|
||||
ui_task.gotoSettingsScreen();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'w':
|
||||
case 'W':
|
||||
// Navigate up/previous (scroll on channel screen)
|
||||
@@ -872,17 +875,6 @@ void handleKeyboardInput() {
|
||||
ui_task.injectKey(0xF2); // KEY_PREV
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
// Navigate down/next (scroll on channel screen)
|
||||
if (ui_task.isOnChannelScreen() || ui_task.isOnContactsScreen()) {
|
||||
ui_task.injectKey('s'); // Pass directly for channel/contacts switching
|
||||
} else {
|
||||
Serial.println("Nav: Next");
|
||||
ui_task.injectKey(0xF1); // KEY_NEXT
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'A':
|
||||
@@ -907,7 +899,7 @@ void handleKeyboardInput() {
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
// Select/Enter - if on contacts screen, enter DM compose for chat contacts
|
||||
// Enter = compose (only from channel or contacts screen)
|
||||
if (ui_task.isOnContactsScreen()) {
|
||||
ContactsScreen* cs = (ContactsScreen*)ui_task.getContactsScreen();
|
||||
int idx = cs->getSelectedContactIdx();
|
||||
@@ -923,12 +915,21 @@ void handleKeyboardInput() {
|
||||
drawComposeScreen();
|
||||
lastComposeRefresh = millis();
|
||||
} else if (idx >= 0) {
|
||||
// Non-chat contact selected (repeater, room, etc.) - future use
|
||||
Serial.printf("Selected non-chat contact type=%d idx=%d\n", ctype, idx);
|
||||
}
|
||||
} else if (ui_task.isOnChannelScreen()) {
|
||||
composeDM = false;
|
||||
composeDMContactIdx = -1;
|
||||
composeChannelIdx = ui_task.getChannelScreenViewIdx();
|
||||
composeMode = true;
|
||||
composeBuffer[0] = '\0';
|
||||
composePos = 0;
|
||||
Serial.printf("Entering compose mode, channel %d\n", composeChannelIdx);
|
||||
drawComposeScreen();
|
||||
lastComposeRefresh = millis();
|
||||
} else {
|
||||
Serial.println("Nav: Enter/Select");
|
||||
ui_task.injectKey(13); // KEY_ENTER
|
||||
// Other screens: pass Enter as generic select
|
||||
ui_task.injectKey(13);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -939,12 +940,6 @@ void handleKeyboardInput() {
|
||||
Serial.println("Nav: Back to home");
|
||||
ui_task.gotoHomeScreen();
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
// Forward to UI for UTC offset editor on GPS page
|
||||
ui_task.injectKey('u');
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
// Space - also acts as next/select
|
||||
@@ -1099,9 +1094,9 @@ void drawEmojiPicker() {
|
||||
|
||||
void sendComposedMessage() {
|
||||
if (composePos == 0) return;
|
||||
|
||||
cpuPower.setBoost(); // Boost CPU for crypto + radio TX
|
||||
|
||||
cpuPower.setBoost(); // Boost CPU for crypto + radio TX
|
||||
|
||||
// Convert escape bytes back to UTF-8 for mesh transmission and BLE app
|
||||
char utf8Buf[512];
|
||||
emojiUnescape(composeBuffer, utf8Buf, sizeof(utf8Buf));
|
||||
|
||||
@@ -603,7 +603,7 @@ private:
|
||||
_currentPage = cache->lastReadPage;
|
||||
}
|
||||
|
||||
// Already fully indexed — open immediately
|
||||
// Already fully indexed — open immediately
|
||||
if (cache->fullyIndexed) {
|
||||
_totalPages = _pagePositions.size();
|
||||
_mode = READING;
|
||||
@@ -613,7 +613,7 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
// Partially indexed — finish indexing with splash
|
||||
// Partially indexed — finish indexing with splash
|
||||
Serial.printf("TextReader: Finishing index for %s (have %d pages so far)\n",
|
||||
actualFilename.c_str(), (int)_pagePositions.size());
|
||||
|
||||
@@ -629,7 +629,7 @@ private:
|
||||
drawSplash("Indexing...", "Please wait", shortName);
|
||||
|
||||
if (_pagePositions.empty()) {
|
||||
// Cache had no pages (e.g. dummy entry) — full index from scratch
|
||||
// Cache had no pages (e.g. dummy entry) — full index from scratch
|
||||
_pagePositions.push_back(0);
|
||||
indexPagesWordWrap(_file, 0, _pagePositions,
|
||||
_linesPerPage, _charsPerLine, 0);
|
||||
@@ -639,7 +639,7 @@ private:
|
||||
_linesPerPage, _charsPerLine, 0);
|
||||
}
|
||||
} else {
|
||||
// No cache — full index from scratch
|
||||
// No cache — full index from scratch
|
||||
Serial.printf("TextReader: Full index for %s\n", actualFilename.c_str());
|
||||
|
||||
char shortName[28];
|
||||
@@ -878,9 +878,8 @@ private:
|
||||
display.drawRect(0, footerY - 2, display.width(), 1);
|
||||
display.setColor(DisplayDriver::YELLOW);
|
||||
|
||||
char status[30];
|
||||
int pct = _totalPages > 1 ? (_currentPage * 100) / (_totalPages - 1) : 100;
|
||||
sprintf(status, "%d/%d %d%%", _currentPage + 1, _totalPages, pct);
|
||||
char status[20];
|
||||
sprintf(status, "%d/%d", _currentPage + 1, _totalPages);
|
||||
display.setCursor(0, footerY);
|
||||
display.print(status);
|
||||
|
||||
@@ -997,7 +996,7 @@ public:
|
||||
|
||||
// --- Pass 1: Fast cache load (no per-file splash screens) ---
|
||||
// Try to load existing .idx files from SD for every file.
|
||||
// This is just SD reads — no indexing, no e-ink refreshes.
|
||||
// This is just SD reads — no indexing, no e-ink refreshes.
|
||||
_fileCache.clear();
|
||||
_fileCache.resize(_fileList.size()); // Pre-allocate slots to maintain alignment with _fileList
|
||||
|
||||
@@ -1026,7 +1025,7 @@ public:
|
||||
// Skip files that loaded from cache
|
||||
if (_fileCache[i].filename.length() > 0) continue;
|
||||
|
||||
// Skip .epub files — they'll be converted on first open via openBook()
|
||||
// Skip .epub files — they'll be converted on first open via openBook()
|
||||
if (_fileList[i].endsWith(".epub") || _fileList[i].endsWith(".EPUB")) {
|
||||
needsIndexCount--; // Don't count epubs in progress display
|
||||
continue;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "ChannelScreen.h"
|
||||
#include "ContactsScreen.h"
|
||||
#include "TextReaderScreen.h"
|
||||
#include "SettingsScreen.h"
|
||||
|
||||
class SplashScreen : public UIScreen {
|
||||
UITask* _task;
|
||||
@@ -372,7 +373,7 @@ public:
|
||||
display.drawTextRightAlign(display.width()-1, y, buf);
|
||||
y = y + 12;
|
||||
|
||||
// NMEA sentence counter — confirms baud rate and data flow
|
||||
// NMEA sentence counter — confirms baud rate and data flow
|
||||
display.drawTextLeftAlign(0, y, "sentences");
|
||||
if (gpsDuty.isHardwareOn()) {
|
||||
uint16_t sps = gpsStream.getSentencesPerSec();
|
||||
@@ -746,6 +747,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
channel_screen = new ChannelScreen(this, &rtc_clock);
|
||||
contacts_screen = new ContactsScreen(this, &rtc_clock);
|
||||
text_reader = new TextReaderScreen(this);
|
||||
settings_screen = new SettingsScreen(this, &rtc_clock, node_prefs);
|
||||
setCurrScreen(splash);
|
||||
}
|
||||
|
||||
@@ -1078,13 +1080,13 @@ void UITask::toggleGPS() {
|
||||
|
||||
if (_sensors != NULL) {
|
||||
if (_node_prefs->gps_enabled) {
|
||||
// Disable GPS — cut hardware power
|
||||
// Disable GPS — cut hardware power
|
||||
_sensors->setSettingValue("gps", "0");
|
||||
_node_prefs->gps_enabled = 0;
|
||||
gpsDuty.disable();
|
||||
notify(UIEventType::ack);
|
||||
} else {
|
||||
// Enable GPS — start duty cycle
|
||||
// Enable GPS — start duty cycle
|
||||
_sensors->setSettingValue("gps", "1");
|
||||
_node_prefs->gps_enabled = 1;
|
||||
gpsDuty.enable();
|
||||
@@ -1182,6 +1184,26 @@ void UITask::gotoTextReader() {
|
||||
_next_refresh = 100;
|
||||
}
|
||||
|
||||
void UITask::gotoSettingsScreen() {
|
||||
((SettingsScreen *) settings_screen)->enter();
|
||||
setCurrScreen(settings_screen);
|
||||
if (_display != NULL && !_display->isOn()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
_next_refresh = 100;
|
||||
}
|
||||
|
||||
void UITask::gotoOnboarding() {
|
||||
((SettingsScreen *) settings_screen)->enterOnboarding();
|
||||
setCurrScreen(settings_screen);
|
||||
if (_display != NULL && !_display->isOn()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
_next_refresh = 100;
|
||||
}
|
||||
|
||||
uint8_t UITask::getChannelScreenViewIdx() const {
|
||||
return ((ChannelScreen *) channel_screen)->getViewChannelIdx();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user