Skip to content

Commit a8cd3ec

Browse files
committed
touch: beer emoji, status-bar unread tap, new-contact toast toggle, Czech accents
- emoji: bake the beer mug U+1F37A and clinking beers U+1F37B as colour glyphs into emoji_data.c (now 252) and add the beer mug to the composer picker; the clinking pair was already listed but only rendered monochrome, now colour. - status bar: tapping the unread badge (envelope + count) on the left now jumps to the Chats inbox. The CLICKABLE flag is toggled per-tick so only the badge state intercepts the tap — every other left-zone state (Back chevron, profile name, OSM credit, blank) keeps the bar's control-center / Back tap. - contacts: add a "Notify on new contact" toggle to the Auto-add page (TouchCfg v8, default ON). When off it suppresses the auto-discovery toast chip in UITask::notify(); the diag-log line and tab badge are unaffected. - keyboard: add the Czech accents c-caron, e-caron, t-caron, z-caron, r-caron and u-ring (plus uppercase) to the long-press / tap accent popup. Glyphs are already baked in the extras fallback fonts, so no font regeneration needed. Builds verified on both LilyGo_TDeck_companion_radio_touch and heltec_v4_tft_companion_radio_usb_tcp_touch. Signed-off-by: Dan Vybiral <dan.vybiral@greencode.cz>
1 parent 11b31e1 commit a8cd3ec

5 files changed

Lines changed: 98 additions & 17 deletions

File tree

src/helpers/esp32/TouchPrefsStore.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static bool s_begun = false;
3535
// short read (→ treat as absent → defaults); `ver` lets later builds add fields.
3636
static const char* KEY_CFG = "cfg";
3737
static const uint16_t TOUCH_CFG_MAGIC = 0x5743; // 'WC' (WadaCfg)
38-
static const uint8_t TOUCH_CFG_VER = 8; // v2 sig_probe/poll; v3 tz_zone; v4 hide_node_name; v5 map_night/map_zoom; v6 map text/marker visibility; v7 app_grid_large; v8 sleep_idle
38+
static const uint8_t TOUCH_CFG_VER = 9; // v2 sig_probe/poll; v3 tz_zone; v4 hide_node_name; v5 map_night/map_zoom; v6 map text/marker visibility; v7 app_grid_large; v8 sleep_idle; v9 notify_new_contact
3939

4040
// Defaults (kept identical to the historical per-key defaults).
4141
static const uint16_t DEFAULT_SCREEN_TIMEOUT_S = 20;
@@ -81,6 +81,7 @@ struct __attribute__((packed)) TouchCfg {
8181
uint8_t map_show_contacts;// show contact markers on the map (bool) — v6
8282
uint8_t app_grid_large; // app drawer: large grid (one fewer column, bigger icons) — v7
8383
uint8_t sleep_idle; // idle light-sleep feature on/off (bool) — v8 (trailing after beta_9's v7 app_grid_large)
84+
uint8_t notify_new_contact;// toast/chip when a contact is auto-discovered (bool) — v9
8485
};
8586

8687
static TouchCfg s_cfg;
@@ -138,6 +139,7 @@ static void cfgSetDefaults(TouchCfg& c) {
138139
c.map_show_contacts = 1;
139140
c.app_grid_large = 0; // default: compact app grid (T-Deck 4 cols / V4 3 cols)
140141
c.sleep_idle = 0; // default: idle light-sleep OFF
142+
c.notify_new_contact = 1; // default: show the new-contact toast (preserve prior behaviour)
141143
}
142144

143145
// Persist the whole blob using the same end()/begin(RW)/put/end()/begin(RO)
@@ -709,6 +711,17 @@ bool touchPrefsSetHideNodeName(bool hide) {
709711
return cfgFlush();
710712
}
711713

714+
bool touchPrefsGetNewContactToast() {
715+
if (!s_begun) touchPrefsBegin();
716+
return s_cfg.notify_new_contact != 0; // default = show the toast
717+
}
718+
719+
bool touchPrefsSetNewContactToast(bool on) {
720+
if (!s_begun) touchPrefsBegin();
721+
s_cfg.notify_new_contact = on ? 1 : 0;
722+
return cfgFlush();
723+
}
724+
712725
bool touchPrefsGetMapNight() {
713726
if (!s_begun) touchPrefsBegin();
714727
return s_cfg.map_night != 0;

src/helpers/esp32/TouchPrefsStore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ bool touchPrefsSetSleepIdle(bool on);
113113
bool touchPrefsGetHideNodeName();
114114
bool touchPrefsSetHideNodeName(bool hide);
115115

116+
/** Show the low-key toast/chip when a contact is auto-discovered/added.
117+
* Default true (toast shown). Off keeps the diag-log line + tab badge. */
118+
bool touchPrefsGetNewContactToast();
119+
bool touchPrefsSetNewContactToast(bool on);
120+
116121
/** Store all device data (identity/prefs/contacts/channels) on the SD card under
117122
* /meshcomod instead of internal SPIFFS. T-Deck only; read at boot before data
118123
* loads, so changing it requires a reboot. Default false (SPIFFS). */

src/ui-touch/UITask.cpp

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,26 +2462,35 @@ static void composerAutoGrowCb(lv_event_t* e) {
24622462
// .cpp) so a hold doesn't auto-repeat — it cleanly long-presses instead.
24632463
static const char* const kAccA[] = {"à","á","â","ä","ã","å"};
24642464
static const char* const kAccA_u[] = {"À","Á","Â","Ä","Ã","Å"};
2465-
static const char* const kAccE[] = {"è","é","ê","ë"};
2466-
static const char* const kAccE_u[] = {"È","É","Ê","Ë"};
2465+
static const char* const kAccE[] = {"è","é","ê","ë","ě"};
2466+
static const char* const kAccE_u[] = {"È","É","Ê","Ë","Ě"};
24672467
static const char* const kAccI[] = {"ì","í","î","ï"};
24682468
static const char* const kAccI_u[] = {"Ì","Í","Î","Ï"};
24692469
static const char* const kAccO[] = {"ò","ó","ô","ö","õ","ø"};
24702470
static const char* const kAccO_u[] = {"Ò","Ó","Ô","Ö","Õ","Ø"};
2471-
static const char* const kAccU[] = {"ù","ú","û","ü"};
2472-
static const char* const kAccU_u[] = {"Ù","Ú","Û","Ü"};
2471+
static const char* const kAccU[] = {"ù","ú","û","ü","ů"};
2472+
static const char* const kAccU_u[] = {"Ù","Ú","Û","Ü","Ů"};
24732473
static const char* const kAccN[] = {"ñ"};
24742474
static const char* const kAccN_u[] = {"Ñ"};
2475-
static const char* const kAccC[] = {"ç"};
2476-
static const char* const kAccC_u[] = {"Ç"};
2475+
static const char* const kAccC[] = {"ç","č"};
2476+
static const char* const kAccC_u[] = {"Ç","Č"};
24772477
static const char* const kAccS[] = {"ß","ś","š"};
24782478
static const char* const kAccY[] = {"ý","ÿ"};
2479+
// Czech carons / ring — base letters that otherwise carry no Latin-1 accent.
2480+
static const char* const kAccT[] = {"ť"};
2481+
static const char* const kAccT_u[] = {"Ť"};
2482+
static const char* const kAccZ[] = {"ž"};
2483+
static const char* const kAccZ_u[] = {"Ž"};
2484+
static const char* const kAccR[] = {"ř"};
2485+
static const char* const kAccR_u[] = {"Ř"};
24792486
struct AccentSet { char key; const char* const* v; uint8_t n; };
24802487
static const AccentSet kAccentSets[] = {
2481-
{'a',kAccA,6},{'A',kAccA_u,6},{'e',kAccE,4},{'E',kAccE_u,4},
2488+
{'a',kAccA,6},{'A',kAccA_u,6},{'e',kAccE,5},{'E',kAccE_u,5},
24822489
{'i',kAccI,4},{'I',kAccI_u,4},{'o',kAccO,6},{'O',kAccO_u,6},
2483-
{'u',kAccU,4},{'U',kAccU_u,4},{'n',kAccN,1},{'N',kAccN_u,1},
2484-
{'c',kAccC,1},{'C',kAccC_u,1},{'s',kAccS,3},{'y',kAccY,2},
2490+
{'u',kAccU,5},{'U',kAccU_u,5},{'n',kAccN,1},{'N',kAccN_u,1},
2491+
{'c',kAccC,2},{'C',kAccC_u,2},{'s',kAccS,3},{'y',kAccY,2},
2492+
{'t',kAccT,1},{'T',kAccT_u,1},{'z',kAccZ,1},{'Z',kAccZ_u,1},
2493+
{'r',kAccR,1},{'R',kAccR_u,1},
24852494
};
24862495
static const AccentSet* accentLookup(const char* key) {
24872496
if (!key || !key[0] || key[1]) return nullptr; // single ASCII-char keys only
@@ -3202,7 +3211,7 @@ static const char* const k_emoji_items[] = {
32023211
"\xF0\x9F\x92\xAF","\xE2\x9C\x85","\xE2\x9D\x8C","\xE2\x9D\x97",
32033212
"\xE2\x9D\x93","\xE2\x9A\xA0","\xF0\x9F\x92\xA9","\xE2\xAD\x90",
32043213
"\xF0\x9F\x8C\x9F","\xE2\x9A\xA1","\xE2\x98\x80","\xE2\x98\x81",
3205-
"\xE2\x9D\x84","\xE2\x98\x94","\xE2\x98\x95","\xF0\x9F\x8D\xBB",
3214+
"\xE2\x9D\x84","\xE2\x98\x94","\xE2\x98\x95","\xF0\x9F\x8D\xBA","\xF0\x9F\x8D\xBB",
32063215
"\xF0\x9F\x8D\x95","\xF0\x9F\x8E\x82","\xF0\x9F\x8E\x81","\xF0\x9F\x92\xAC",
32073216
"\xF0\x9F\x92\xA4","\xF0\x9F\x92\xA5",
32083217
// objects
@@ -5271,6 +5280,14 @@ static void buildRadioSettings() {
52715280
lv_obj_center(l);
52725281
}
52735282

5283+
// New-contact toast toggle (Auto-add page). Persists immediately like the
5284+
// auto-add switches; default ON. Diag-log line + tab badge are unaffected — this
5285+
// only gates the low-key chip in UITask::notify().
5286+
static void toggleNewContactToastCb(lv_event_t* e) {
5287+
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
5288+
touchPrefsSetNewContactToast(lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED));
5289+
}
5290+
52745291
static void buildAutoAddSettings() {
52755292
lv_obj_t* body = createSettingsModal("Auto-add contacts", SettingsModalKind::AutoAdd);
52765293
NodePrefs* prefs = the_mesh.getNodePrefs();
@@ -5290,6 +5307,17 @@ static void buildAutoAddSettings() {
52905307
mk_switch("Overwrite oldest", &g_set_modal.auto_overwrite_sw);
52915308
g_set_modal.manual_add_sw = nullptr; // master "manual add" removed — per-type switches are authoritative now
52925309

5310+
// "Notify on new contact" — a UI pref (not a NodePrefs autoadd bit), so it gets
5311+
// its own callback + persistence rather than mk_switch's autoAddSwitchCb.
5312+
{
5313+
int h = settingsRowLabel(body, y, 6, "Notify on new contact", COLOR_SUB, nullptr, 56);
5314+
lv_obj_t* sw = lv_switch_create(body);
5315+
lv_obj_align(sw, LV_ALIGN_TOP_RIGHT, 0, y);
5316+
if (touchPrefsGetNewContactToast()) lv_obj_add_state(sw, LV_STATE_CHECKED);
5317+
lv_obj_add_event_cb(sw, toggleNewContactToastCb, LV_EVENT_VALUE_CHANGED, nullptr);
5318+
y += LV_MAX(34, h + 12);
5319+
}
5320+
52935321
lv_obj_t* hops_l = lv_label_create(body);
52945322
lv_label_set_text(hops_l, TR("Max hops (0..64)"));
52955323
lv_obj_set_style_text_color(hops_l, lv_color_hex(COLOR_SUB), LV_PART_MAIN);
@@ -13408,6 +13436,14 @@ static void homeUnreadClickedCb(lv_event_t* e) {
1340813436
goToTab(CHAT_INBOX_TAB_INDEX);
1340913437
}
1341013438

13439+
// Status-bar unread badge (✉ N) → Chats inbox. Wired on the bar's left_label;
13440+
// only fires while updateGlobalStatusBar has flagged the badge state CLICKABLE,
13441+
// so non-badge left-zone states keep the bar's control-center / Back tap.
13442+
static void statusBarUnreadCb(lv_event_t* e) {
13443+
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
13444+
goToTab(CHAT_INBOX_TAB_INDEX);
13445+
}
13446+
1341113447
// ---- App drawer (full-screen grid launcher) ----
1341213448
// A toggle-in alternative to the command-centre home. The full implementation
1341313449
// lives below openControlCenter (it links to the tool openers defined there);
@@ -22920,6 +22956,11 @@ static void buildGlobalStatusBar() {
2292022956
lv_obj_set_style_text_color(g_statusbar.left_label, lv_color_hex(COLOR_TEXT), LV_PART_MAIN);
2292122957
lv_obj_set_style_text_font(g_statusbar.left_label, &g_font_14, LV_PART_MAIN);
2292222958
lv_obj_align(g_statusbar.left_label, LV_ALIGN_LEFT_MID, 6, 0);
22959+
// Tapping the unread badge (✉ N) jumps to the Chats inbox. The CLICKABLE flag is
22960+
// toggled per-tick in updateGlobalStatusBar so only the badge state intercepts the
22961+
// tap; every other left-zone state falls through to the bar's control-center tap.
22962+
lv_obj_set_ext_click_area(g_statusbar.left_label, 8);
22963+
lv_obj_add_event_cb(g_statusbar.left_label, statusBarUnreadCb, LV_EVENT_CLICKED, nullptr);
2292322964

2292422965
// Channel-settings gear — left of the thread name, shown only inside a channel
2292522966
// chat (updateGlobalStatusBar toggles it + shifts the name). Opens the
@@ -23088,6 +23129,7 @@ static void updateGlobalStatusBar() {
2308823129
}
2308923130

2309023131
// ---- Left zone ----
23132+
bool unread_badge = false; // set true only by the branches that render the ✉ count
2309123133
if (s_settings_open_cat >= 0) {
2309223134
// A settings detail sheet is open: the bar carries its Back chevron + the page
2309323135
// title (the sheet has no header of its own; tapping the bar goes Back).
@@ -23108,6 +23150,7 @@ static void updateGlobalStatusBar() {
2310823150
if (total_unread > 99) snprintf(ub, sizeof ub, "99+"); else snprintf(ub, sizeof ub, "%d", total_unread);
2310923151
snprintf(buf, sizeof(buf), LV_SYMBOL_ENVELOPE " %s %s", ub, s_chat_title);
2311023152
lv_label_set_text(g_statusbar.left_label, buf);
23153+
unread_badge = true;
2311123154
} else {
2311223155
lv_label_set_text(g_statusbar.left_label, s_chat_title);
2311323156
}
@@ -23164,6 +23207,7 @@ static void updateGlobalStatusBar() {
2316423207
if (total_unread > 99) snprintf(buf, sizeof(buf), LV_SYMBOL_ENVELOPE " 99+");
2316523208
else snprintf(buf, sizeof(buf), LV_SYMBOL_ENVELOPE " %d", total_unread);
2316623209
lv_label_set_text(g_statusbar.left_label, buf);
23210+
unread_badge = true;
2316723211
} else {
2316823212
// No unread → blank the left zone entirely. Operator complaint was
2316923213
// the envelope was always lit even with an empty inbox, which read
@@ -23173,6 +23217,14 @@ static void updateGlobalStatusBar() {
2317323217
}
2317423218
}
2317523219

23220+
// Activate the unread→Chats shortcut only while the ✉ count is shown; other
23221+
// left-zone states (Back chevron, profile name, OSM credit, blank) keep the
23222+
// bar's normal control-center / Back tap.
23223+
if (g_statusbar.left_label) {
23224+
if (unread_badge) lv_obj_add_flag(g_statusbar.left_label, LV_OBJ_FLAG_CLICKABLE);
23225+
else lv_obj_clear_flag(g_statusbar.left_label, LV_OBJ_FLAG_CLICKABLE);
23226+
}
23227+
2317623228
// ---- Connection icon ----
2317723229
#if defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION)
2317823230
const bool wifi_up = (WiFi.status() == WL_CONNECTED);
@@ -27935,12 +27987,17 @@ void UITask::notify(UIEventType t) {
2793527987
}
2793627988
// Background traffic (also reflected in the tab badges): show a subtle, low-key
2793727989
// chip rather than the prominent centre alert toast, so it's less intrusive.
27938-
strncpy(_alert, msg, sizeof(_alert) - 1);
27939-
_alert[sizeof(_alert) - 1] = '\0';
27940-
_alert_expiry = millis() + 1100UL;
27990+
// New-contact discovery can be spammy in a busy mesh, so its chip is opt-out in
27991+
// Settings -> Auto-add; when suppressed we still log the diag line + tab badge.
27992+
const bool toast = (t != UIEventType::newContactMessage) || touchPrefsGetNewContactToast();
27993+
if (toast) {
27994+
strncpy(_alert, msg, sizeof(_alert) - 1);
27995+
_alert[sizeof(_alert) - 1] = '\0';
27996+
_alert_expiry = millis() + 1100UL;
27997+
}
2794127998
#if defined(HAS_TOUCH_UI)
2794227999
pushDiagLine(msg);
27943-
showSubtleNotifyLvgl(msg, 1100);
28000+
if (toast) showSubtleNotifyLvgl(msg, 1100);
2794428001
#endif
2794528002
}
2794628003

0 commit comments

Comments
 (0)