mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-02 02:06:11 +00:00
refactor(ui): share single KeyboardWidget instance across screens
Moves KeyboardWidget from a per-screen value member to a single instance owned by UITask, passed to SettingsScreen, QuickMsgScreen, and BotScreen as a pointer. Only one screen is ever active at a time, so the shared state is safe. Saves ~1.5 KB of always-resident heap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
2d6d35192b
commit
c339dc7d97
@@ -13,8 +13,8 @@ class BotScreen : public UIScreen {
|
|||||||
bool _dirty;
|
bool _dirty;
|
||||||
|
|
||||||
// keyboard state (reused for trigger and reply fields)
|
// keyboard state (reused for trigger and reply fields)
|
||||||
int _kb_field; // -1=off, 2=trigger, 3=reply DM, 4=reply Ch
|
int _kb_field; // -1=off, 2=trigger, 3=reply DM, 4=reply Ch
|
||||||
KeyboardWidget _kb;
|
KeyboardWidget* _kb;
|
||||||
|
|
||||||
// channel cache (refreshed on enter)
|
// channel cache (refreshed on enter)
|
||||||
int _num_channels;
|
int _num_channels;
|
||||||
@@ -38,7 +38,7 @@ class BotScreen : public UIScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BotScreen(UITask* task, NodePrefs* prefs) : _task(task), _prefs(prefs) {}
|
BotScreen(UITask* task, NodePrefs* prefs, KeyboardWidget* kb) : _task(task), _prefs(prefs), _kb(kb) {}
|
||||||
|
|
||||||
void enter() {
|
void enter() {
|
||||||
_sel = 0;
|
_sel = 0;
|
||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
|
|
||||||
if (_kb_field >= 0) {
|
if (_kb_field >= 0) {
|
||||||
return _kb.render(display);
|
return _kb->render(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
int avail_h = display.height() - display.listStart();
|
int avail_h = display.height() - display.listStart();
|
||||||
@@ -109,17 +109,17 @@ public:
|
|||||||
bool cancel = (c == KEY_CANCEL || c == KEY_CONTEXT_MENU);
|
bool cancel = (c == KEY_CANCEL || c == KEY_CONTEXT_MENU);
|
||||||
|
|
||||||
if (_kb_field >= 0) {
|
if (_kb_field >= 0) {
|
||||||
auto res = _kb.handleInput(c);
|
auto res = _kb->handleInput(c);
|
||||||
if (res == KeyboardWidget::DONE) {
|
if (res == KeyboardWidget::DONE) {
|
||||||
if (_kb_field == 2) {
|
if (_kb_field == 2) {
|
||||||
strncpy(_prefs->bot_trigger, _kb.buf, sizeof(_prefs->bot_trigger) - 1);
|
strncpy(_prefs->bot_trigger, _kb->buf, sizeof(_prefs->bot_trigger) - 1);
|
||||||
_prefs->bot_trigger[sizeof(_prefs->bot_trigger) - 1] = '\0';
|
_prefs->bot_trigger[sizeof(_prefs->bot_trigger) - 1] = '\0';
|
||||||
for (char* p = _prefs->bot_trigger; *p; p++) *p = (char)tolower((uint8_t)*p);
|
for (char* p = _prefs->bot_trigger; *p; p++) *p = (char)tolower((uint8_t)*p);
|
||||||
} else if (_kb_field == 3) {
|
} else if (_kb_field == 3) {
|
||||||
strncpy(_prefs->bot_reply_dm, _kb.buf, sizeof(_prefs->bot_reply_dm) - 1);
|
strncpy(_prefs->bot_reply_dm, _kb->buf, sizeof(_prefs->bot_reply_dm) - 1);
|
||||||
_prefs->bot_reply_dm[sizeof(_prefs->bot_reply_dm) - 1] = '\0';
|
_prefs->bot_reply_dm[sizeof(_prefs->bot_reply_dm) - 1] = '\0';
|
||||||
} else {
|
} else {
|
||||||
strncpy(_prefs->bot_reply_ch, _kb.buf, sizeof(_prefs->bot_reply_ch) - 1);
|
strncpy(_prefs->bot_reply_ch, _kb->buf, sizeof(_prefs->bot_reply_ch) - 1);
|
||||||
_prefs->bot_reply_ch[sizeof(_prefs->bot_reply_ch) - 1] = '\0';
|
_prefs->bot_reply_ch[sizeof(_prefs->bot_reply_ch) - 1] = '\0';
|
||||||
}
|
}
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
@@ -180,9 +180,9 @@ public:
|
|||||||
initial = _prefs->bot_reply_ch;
|
initial = _prefs->bot_reply_ch;
|
||||||
max = sizeof(_prefs->bot_reply_ch) - 1;
|
max = sizeof(_prefs->bot_reply_ch) - 1;
|
||||||
}
|
}
|
||||||
_kb.begin(initial, max);
|
_kb->begin(initial, max);
|
||||||
if (_sel == 2) {
|
if (_sel == 2) {
|
||||||
_kb.clearPlaceholders(); // trigger is literal text — placeholders never match incoming msgs
|
_kb->clearPlaceholders(); // trigger is literal text — placeholders never match incoming msgs
|
||||||
} else {
|
} else {
|
||||||
kbAddSensorPlaceholders(_kb, &sensors);
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class QuickMsgScreen : public UIScreen {
|
|||||||
static const int CH_HIST_MAX = 96;
|
static const int CH_HIST_MAX = 96;
|
||||||
|
|
||||||
// KEYBOARD
|
// KEYBOARD
|
||||||
KeyboardWidget _kb;
|
KeyboardWidget* _kb;
|
||||||
|
|
||||||
// Context menu (opened by KEY_CONTEXT_MENU in CHANNEL_PICK / CONTACT_PICK / histories)
|
// Context menu (opened by KEY_CONTEXT_MENU in CHANNEL_PICK / CONTACT_PICK / histories)
|
||||||
PopupMenu _ctx_menu;
|
PopupMenu _ctx_menu;
|
||||||
@@ -152,7 +152,7 @@ class QuickMsgScreen : public UIScreen {
|
|||||||
void beginShareCompose(bool channel) {
|
void beginShareCompose(bool channel) {
|
||||||
_sending_to_channel = channel;
|
_sending_to_channel = channel;
|
||||||
_reply_mode = false;
|
_reply_mode = false;
|
||||||
_kb.begin(_share_text);
|
_kb->begin(_share_text);
|
||||||
_phase = KEYBOARD;
|
_phase = KEYBOARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,8 +494,8 @@ class QuickMsgScreen : public UIScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QuickMsgScreen(UITask* task)
|
QuickMsgScreen(UITask* task, KeyboardWidget* kb)
|
||||||
: _task(task), _phase(MODE_SELECT), _mode_sel(0),
|
: _task(task), _kb(kb), _phase(MODE_SELECT), _mode_sel(0),
|
||||||
_contact_sel(0), _contact_scroll(0), _num_contacts(0), _room_mode(false),
|
_contact_sel(0), _contact_scroll(0), _num_contacts(0), _room_mode(false),
|
||||||
_channel_sel(0), _channel_scroll(0), _num_channels(0),
|
_channel_sel(0), _channel_scroll(0), _num_channels(0),
|
||||||
_sel_channel_idx(0), _sending_to_channel(false),
|
_sel_channel_idx(0), _sending_to_channel(false),
|
||||||
@@ -1045,7 +1045,7 @@ public:
|
|||||||
if (_ctx_menu.active) _ctx_menu.render(display);
|
if (_ctx_menu.active) _ctx_menu.render(display);
|
||||||
|
|
||||||
} else if (_phase == KEYBOARD) {
|
} else if (_phase == KEYBOARD) {
|
||||||
return _kb.render(display);
|
return _kb->render(display);
|
||||||
|
|
||||||
} else { // MSG_PICK
|
} else { // MSG_PICK
|
||||||
char title[24];
|
char title[24];
|
||||||
@@ -1540,21 +1540,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (_phase == KEYBOARD) {
|
} else if (_phase == KEYBOARD) {
|
||||||
auto res = _kb.handleInput(c);
|
auto res = _kb->handleInput(c);
|
||||||
if (res == KeyboardWidget::CANCELLED) {
|
if (res == KeyboardWidget::CANCELLED) {
|
||||||
if (_share_mode) { _share_mode = false; _task->gotoHomeScreen(); }
|
if (_share_mode) { _share_mode = false; _task->gotoHomeScreen(); }
|
||||||
else { _phase = MSG_PICK; }
|
else { _phase = MSG_PICK; }
|
||||||
} else if (res == KeyboardWidget::DONE) {
|
} else if (res == KeyboardWidget::DONE) {
|
||||||
int prefix_len = _reply_mode ? (int)strlen(_reply_prefix) : 0;
|
int prefix_len = _reply_mode ? (int)strlen(_reply_prefix) : 0;
|
||||||
if (_kb.len > prefix_len) {
|
if (_kb->len > prefix_len) {
|
||||||
// Expand only the body — prefix "@[nick] " is preserved verbatim, so a nick
|
// Expand only the body — prefix "@[nick] " is preserved verbatim, so a nick
|
||||||
// that happens to contain a placeholder token isn't substituted.
|
// that happens to contain a placeholder token isn't substituted.
|
||||||
char expanded[KB_MAX_LEN + 1];
|
char expanded[KB_MAX_LEN + 1];
|
||||||
if (prefix_len > 0) {
|
if (prefix_len > 0) {
|
||||||
memcpy(expanded, _kb.buf, prefix_len);
|
memcpy(expanded, _kb->buf, prefix_len);
|
||||||
expandMsg(_kb.buf + prefix_len, expanded + prefix_len, sizeof(expanded) - prefix_len);
|
expandMsg(_kb->buf + prefix_len, expanded + prefix_len, sizeof(expanded) - prefix_len);
|
||||||
} else {
|
} else {
|
||||||
expandMsg(_kb.buf, expanded, sizeof(expanded));
|
expandMsg(_kb->buf, expanded, sizeof(expanded));
|
||||||
}
|
}
|
||||||
bool ok = sendText(expanded);
|
bool ok = sendText(expanded);
|
||||||
afterSend(ok, expanded);
|
afterSend(ok, expanded);
|
||||||
@@ -1581,7 +1581,7 @@ public:
|
|||||||
}
|
}
|
||||||
if (c == KEY_ENTER) {
|
if (c == KEY_ENTER) {
|
||||||
if (_msg_sel == 0) {
|
if (_msg_sel == 0) {
|
||||||
_kb.begin(_reply_mode ? _reply_prefix : "");
|
_kb->begin(_reply_mode ? _reply_prefix : "");
|
||||||
kbAddSensorPlaceholders(_kb, &sensors);
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
_phase = KEYBOARD;
|
_phase = KEYBOARD;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -572,12 +572,12 @@ class SettingsScreen : public UIScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard state for editing message slots
|
// Keyboard state for editing message slots
|
||||||
int _edit_slot; // -1 = not editing, 0..9 = slot being edited
|
int _edit_slot; // -1 = not editing, 0..9 = slot being edited
|
||||||
KeyboardWidget _kb;
|
KeyboardWidget* _kb;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SettingsScreen(UITask* task)
|
SettingsScreen(UITask* task, KeyboardWidget* kb)
|
||||||
: _task(task), _selected(SECTION_DISPLAY), _scroll(0), _visible(4), _dirty(false), _edit_slot(-1) {
|
: _task(task), _kb(kb), _selected(SECTION_DISPLAY), _scroll(0), _visible(4), _dirty(false), _edit_slot(-1) {
|
||||||
buildVis();
|
buildVis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +594,7 @@ public:
|
|||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
|
|
||||||
if (_edit_slot >= 0) {
|
if (_edit_slot >= 0) {
|
||||||
return _kb.render(display);
|
return _kb->render(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
int item_h = display.lineStep();
|
int item_h = display.lineStep();
|
||||||
@@ -629,10 +629,10 @@ public:
|
|||||||
|
|
||||||
// Keyboard editing mode for message slots
|
// Keyboard editing mode for message slots
|
||||||
if (_edit_slot >= 0) {
|
if (_edit_slot >= 0) {
|
||||||
auto res = _kb.handleInput(c);
|
auto res = _kb->handleInput(c);
|
||||||
if (res == KeyboardWidget::DONE) {
|
if (res == KeyboardWidget::DONE) {
|
||||||
if (p) {
|
if (p) {
|
||||||
strncpy(p->custom_msgs[_edit_slot], _kb.buf, sizeof(p->custom_msgs[0]) - 1);
|
strncpy(p->custom_msgs[_edit_slot], _kb->buf, sizeof(p->custom_msgs[0]) - 1);
|
||||||
p->custom_msgs[_edit_slot][sizeof(p->custom_msgs[0]) - 1] = '\0';
|
p->custom_msgs[_edit_slot][sizeof(p->custom_msgs[0]) - 1] = '\0';
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
}
|
}
|
||||||
@@ -834,7 +834,7 @@ public:
|
|||||||
_edit_slot = slot;
|
_edit_slot = slot;
|
||||||
// Bound to the custom_msgs store (140 B) so the wider keyboard buffer
|
// Bound to the custom_msgs store (140 B) so the wider keyboard buffer
|
||||||
// can't overflow it on save.
|
// can't overflow it on save.
|
||||||
_kb.begin(p ? p->custom_msgs[slot] : "",
|
_kb->begin(p ? p->custom_msgs[slot] : "",
|
||||||
p ? (int)sizeof(p->custom_msgs[slot]) - 1 : KB_MAX_LEN);
|
p ? (int)sizeof(p->custom_msgs[slot]) - 1 : KB_MAX_LEN);
|
||||||
kbAddSensorPlaceholders(_kb, &sensors);
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ public:
|
|||||||
static const int QUICK_MSGS_MAX = 10;
|
static const int QUICK_MSGS_MAX = 10;
|
||||||
|
|
||||||
|
|
||||||
#include "KeyboardWidget.h"
|
|
||||||
#include "FullscreenMsgView.h"
|
#include "FullscreenMsgView.h"
|
||||||
#include "SensorPlaceholders.h"
|
#include "SensorPlaceholders.h"
|
||||||
#include "SettingsScreen.h"
|
#include "SettingsScreen.h"
|
||||||
@@ -1198,11 +1197,11 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
|||||||
|
|
||||||
splash = new SplashScreen(this);
|
splash = new SplashScreen(this);
|
||||||
home = new HomeScreen(this, &rtc_clock, sensors, node_prefs);
|
home = new HomeScreen(this, &rtc_clock, sensors, node_prefs);
|
||||||
settings = new SettingsScreen(this);
|
settings = new SettingsScreen(this, &_kb);
|
||||||
quick_msg = new QuickMsgScreen(this);
|
quick_msg = new QuickMsgScreen(this, &_kb);
|
||||||
tools_screen = new ToolsScreen(this);
|
tools_screen = new ToolsScreen(this);
|
||||||
ringtone_edit = new RingtoneEditorScreen(this, node_prefs);
|
ringtone_edit = new RingtoneEditorScreen(this, node_prefs);
|
||||||
bot_screen = new BotScreen(this, node_prefs);
|
bot_screen = new BotScreen(this, node_prefs, &_kb);
|
||||||
nearby_screen = new NearbyScreen(this);
|
nearby_screen = new NearbyScreen(this);
|
||||||
dashboard_config = new DashboardConfigScreen(this, node_prefs);
|
dashboard_config = new DashboardConfigScreen(this, node_prefs);
|
||||||
auto_advert_screen = new AutoAdvertScreen(this, node_prefs);
|
auto_advert_screen = new AutoAdvertScreen(this, node_prefs);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "../NodePrefs.h"
|
#include "../NodePrefs.h"
|
||||||
#include "../Trail.h"
|
#include "../Trail.h"
|
||||||
#include "../Waypoint.h"
|
#include "../Waypoint.h"
|
||||||
|
#include "KeyboardWidget.h"
|
||||||
|
|
||||||
class UITask : public AbstractUITask {
|
class UITask : public AbstractUITask {
|
||||||
DisplayDriver* _display;
|
DisplayDriver* _display;
|
||||||
@@ -43,6 +44,7 @@ class UITask : public AbstractUITask {
|
|||||||
bool _lock_seq_used; // true = suppress next back_btn CLICK (post-sequence release)
|
bool _lock_seq_used; // true = suppress next back_btn CLICK (post-sequence release)
|
||||||
char _alert[80];
|
char _alert[80];
|
||||||
char _notif_mel_buf[220]; // persistent RTTTL buffer for custom notification melodies
|
char _notif_mel_buf[220]; // persistent RTTTL buffer for custom notification melodies
|
||||||
|
KeyboardWidget _kb; // shared across all screens — only one active at a time
|
||||||
unsigned long _alert_expiry;
|
unsigned long _alert_expiry;
|
||||||
int _msgcount;
|
int _msgcount;
|
||||||
int _room_unread;
|
int _room_unread;
|
||||||
|
|||||||
Reference in New Issue
Block a user