Files
HaloKeymind/examples/simple_repeater/UITask.h
T
agessaman 3e7e0322e5 fix(display): make the USER button click immediate, 3 s hold to power off
Power-off now needs a 3 second hold; any shorter press toggles the display.
MomentaryButton reports a CLICK for any release short of its threshold, so
that single value defines both.

The button also felt unreliable - "a brief press doesn't wake it, more often
than not". MomentaryButton's multi-click detection withholds a CLICK for
MULTI_CLICK_WINDOW_MS (280 ms) after release, and folds a second press
arriving inside that window into a DOUBLE_CLICK. Since the handler only acts
on CLICK, an impatient second press produced nothing at all: press, see
nothing, press again, still nothing. Multi-click is now off for these targets,
so CLICK fires on release.

Both settings are build flags defaulted in variants/heltec_v4_r8/target.cpp
and overridden only on the two TFT observer bases, because the companion
builds share this user_btn and do use double/triple click.

DISPLAY_TOUCH_DEBUG additionally logs which input caused a toggle
("Display: button -> on"), so any remaining flake can be attributed to the
button or to a spurious touch read rather than guessed at.
2026-08-28 15:37:09 -07:00

80 lines
2.2 KiB
C++

#pragma once
#include <helpers/ui/DisplayDriver.h>
#include <helpers/CommonCLI.h>
#ifdef DISPLAY_ACTIVITY_DASHBOARD
#ifndef DISPLAY_REDRAW_ON_CHANGE
#error "DISPLAY_ACTIVITY_DASHBOARD needs DISPLAY_REDRAW_ON_CHANGE: without it every frame clears the whole screen"
#endif
#include <helpers/RadioActivityWindow.h>
#include <helpers/ui/ObserverDashboard.h>
#endif
#ifdef DISPLAY_TOUCH_TOGGLE
#include <helpers/ui/CHSC6XTouch.h>
#endif
class UITask {
mesh::MainBoard* _board;
DisplayDriver* _display;
unsigned long _next_read, _next_refresh, _auto_off;
int _prevBtnState;
NodePrefs* _node_prefs;
char _version_info[32];
unsigned long _powering_off_at = 0;
unsigned long _started_at = 0;
#ifdef DISPLAY_REDRAW_ON_CHANGE
uint32_t _last_frame_signature = 0;
bool _frame_valid = false;
uint32_t getFrameSignature();
#endif
#ifdef DISPLAY_ACTIVITY_DASHBOARD
RadioActivityWindow* _activity = NULL;
unsigned long _next_activity = 0;
uint32_t _row_signatures[ObserverDashboard::ROW_COUNT] = {0};
bool _rows_valid = false; // true only while the dashboard is the drawn screen
bool buildDashboardContext(ObserverDashboard::Context* ctx);
void renderDashboard();
void updateActivityRows();
#endif
#ifdef DISPLAY_TOUCH_TOGGLE
CHSC6XTouch _touch;
unsigned long _next_touch = 0;
void toggleDisplay(const char* source);
#endif
#ifdef WITH_MQTT_BRIDGE
MQTTPrefs* _observer_prefs = NULL;
#endif
unsigned long _timeout_seen = 0; // to notice a live `display.timeout` change
uint8_t _flip_seen = 0xFF; // 0xFF forces the first apply
void applyDisplayFlip();
unsigned long displayTimeoutMillis() const;
void renderCurrScreen();
public:
UITask(mesh::MainBoard& board, DisplayDriver& display) : _board(&board), _display(&display) { _next_read = _next_refresh = 0; }
void begin(NodePrefs* node_prefs, const char* build_date, const char* firmware_version);
#ifdef WITH_MQTT_BRIDGE
// Supplies `display.timeout`, which is read live so a config change applies
// without a reboot. Call before begin().
void setObserverPrefs(MQTTPrefs* prefs) { _observer_prefs = prefs; }
#endif
#ifdef DISPLAY_ACTIVITY_DASHBOARD
void setActivityWindow(RadioActivityWindow* activity) { _activity = activity; }
#endif
void loop();
};