mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-20 00:31:09 +00:00
Simple Menu Queue, and add time menu
This commit is contained in:
parent
60acba877e
commit
b55e763b29
@ -136,13 +136,14 @@ extern bool hasUnreadMessage;
|
|||||||
// The banner appears in the center of the screen and disappears after the specified duration
|
// The banner appears in the center of the screen and disappears after the specified duration
|
||||||
|
|
||||||
// Called to trigger a banner with custom message and duration
|
// Called to trigger a banner with custom message and duration
|
||||||
void Screen::showOverlayBanner(const char *message, uint32_t durationMs, uint8_t options, std::function<void(int)> bannerCallback,
|
void Screen::showOverlayBanner(const char *message, uint32_t durationMs, const char **optionsArrayPtr, uint8_t options,
|
||||||
int8_t InitialSelected)
|
std::function<void(int)> bannerCallback, int8_t InitialSelected)
|
||||||
{
|
{
|
||||||
// Store the message and set the expiration timestamp
|
// Store the message and set the expiration timestamp
|
||||||
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
||||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||||
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||||
|
NotificationRenderer::optionsArrayPtr = optionsArrayPtr;
|
||||||
NotificationRenderer::alertBannerOptions = options;
|
NotificationRenderer::alertBannerOptions = options;
|
||||||
NotificationRenderer::alertBannerCallback = bannerCallback;
|
NotificationRenderer::alertBannerCallback = bannerCallback;
|
||||||
NotificationRenderer::curSelected = InitialSelected;
|
NotificationRenderer::curSelected = InitialSelected;
|
||||||
@ -559,6 +560,7 @@ int32_t Screen::runOnce()
|
|||||||
if (displayHeight == 0) {
|
if (displayHeight == 0) {
|
||||||
displayHeight = dispdev->getHeight();
|
displayHeight = dispdev->getHeight();
|
||||||
}
|
}
|
||||||
|
handleMenuSwitch();
|
||||||
|
|
||||||
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
||||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||||
@ -1210,6 +1212,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||||
setFastFramerate(); // Draw ASAP
|
setFastFramerate(); // Draw ASAP
|
||||||
ui->update();
|
ui->update();
|
||||||
|
|
||||||
|
handleMenuSwitch();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1247,16 +1251,18 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
showNextFrame();
|
showNextFrame();
|
||||||
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
||||||
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
||||||
const char *banner_message;
|
static const char **optionsArrayPtr;
|
||||||
int options;
|
int options;
|
||||||
if (kb_found) {
|
if (kb_found) {
|
||||||
banner_message = "Action?\nBack\nSleep Screen\nNew Preset Msg\nNew Freetext Msg";
|
const char *optionsArray[] = {"Action?", "Back", "Sleep Screen", "New Preset Msg", "New Freetext Msg"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 4;
|
options = 4;
|
||||||
} else {
|
} else {
|
||||||
banner_message = "Action?\nBack\nSleep Screen\nNew Preset Msg";
|
const char *optionsArray[] = {"Action?", "Back", "Sleep Screen", "New Preset Msg"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 3;
|
options = 3;
|
||||||
}
|
}
|
||||||
showOverlayBanner(banner_message, 30000, options, [](int selected) -> void {
|
showOverlayBanner("Action?", 30000, optionsArrayPtr, options, [](int selected) -> void {
|
||||||
if (selected == 1) {
|
if (selected == 1) {
|
||||||
screen->setOn(false);
|
screen->setOn(false);
|
||||||
} else if (selected == 2) {
|
} else if (selected == 2) {
|
||||||
@ -1267,7 +1273,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
});
|
});
|
||||||
#if HAS_TFT
|
#if HAS_TFT
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||||
showOverlayBanner("Switch to MUI?\nYes\nNo", 30000, 2, [](int selected) -> void {
|
static const char *optionsArray[] = {"Yes", "No"};
|
||||||
|
showOverlayBanner("Switch to MUI?", 30000, optionsArray, 2, [](int selected) -> void {
|
||||||
if (selected == 0) {
|
if (selected == 0) {
|
||||||
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR;
|
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR;
|
||||||
config.bluetooth.enabled = false;
|
config.bluetooth.enabled = false;
|
||||||
@ -1277,8 +1284,9 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||||
|
static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"};
|
||||||
showOverlayBanner(
|
showOverlayBanner(
|
||||||
"Beeps Mode\nAll Enabled\nDisabled\nNotifications\nSystem Only", 30000, 4,
|
"Beeps Mode", 30000, optionsArray, 4,
|
||||||
[](int selected) -> void {
|
[](int selected) -> void {
|
||||||
config.device.buzzer_mode = (meshtastic_Config_DeviceConfig_BuzzerMode)selected;
|
config.device.buzzer_mode = (meshtastic_Config_DeviceConfig_BuzzerMode)selected;
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
@ -1287,8 +1295,9 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
#endif
|
#endif
|
||||||
#if HAS_GPS
|
#if HAS_GPS
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
||||||
|
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||||
showOverlayBanner(
|
showOverlayBanner(
|
||||||
"Toggle GPS\nBack\nEnabled\nDisabled", 30000, 3,
|
"Toggle GPS", 30000, optionsArray, 3,
|
||||||
[](int selected) -> void {
|
[](int selected) -> void {
|
||||||
if (selected == 1) {
|
if (selected == 1) {
|
||||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||||
@ -1306,25 +1315,39 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
: 2); // set inital selection
|
: 2); // set inital selection
|
||||||
#endif
|
#endif
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
|
||||||
TZPicker();
|
static const char *optionsArray[] = {"Back", "12-hour", "Timezone"};
|
||||||
|
showOverlayBanner("Clock Menu", 30000, optionsArray, 3, [](int selected) -> void {
|
||||||
|
if (selected == 1) {
|
||||||
|
screen->menuQueue = screen->twelve_hour_picker;
|
||||||
|
screen->setInterval(0);
|
||||||
|
runASAP = true;
|
||||||
|
} else if (selected == 2) {
|
||||||
|
screen->menuQueue = screen->TZ_picker;
|
||||||
|
screen->setInterval(0);
|
||||||
|
runASAP = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
|
||||||
LoraRegionPicker();
|
LoraRegionPicker();
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage &&
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage &&
|
||||||
devicestate.rx_text_message.from) {
|
devicestate.rx_text_message.from) {
|
||||||
const char *banner_message;
|
static const char **optionsArrayPtr;
|
||||||
int options;
|
int options;
|
||||||
if (kb_found) {
|
if (kb_found) {
|
||||||
banner_message = "Message Action?\nBack\nDismiss\nReply via Preset\nReply via Freetext";
|
const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 4;
|
options = 4;
|
||||||
} else {
|
} else {
|
||||||
banner_message = "Message Action?\nBack\nDismiss\nReply via Preset";
|
const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 3;
|
options = 3;
|
||||||
}
|
}
|
||||||
#ifdef HAS_I2S
|
#ifdef HAS_I2S
|
||||||
banner_message = "Message Action?\nBack\nDismiss\nReply via Preset\nReply via Freetext\nRead Aloud";
|
const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext", "Read Aloud"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 5;
|
options = 5;
|
||||||
#endif
|
#endif
|
||||||
showOverlayBanner(banner_message, 30000, options, [](int selected) -> void {
|
showOverlayBanner("Message Action?", 30000, optionsArrayPtr, options, [](int selected) -> void {
|
||||||
if (selected == 1) {
|
if (selected == 1) {
|
||||||
screen->dismissCurrentFrame();
|
screen->dismissCurrentFrame();
|
||||||
} else if (selected == 2) {
|
} else if (selected == 2) {
|
||||||
@ -1354,16 +1377,19 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
||||||
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
||||||
this->ui->getUiState()->currentFrame <= framesetInfo.positions.lastFavorite) {
|
this->ui->getUiState()->currentFrame <= framesetInfo.positions.lastFavorite) {
|
||||||
const char *banner_message;
|
|
||||||
int options;
|
int options;
|
||||||
|
static const char **optionsArrayPtr;
|
||||||
|
|
||||||
if (kb_found) {
|
if (kb_found) {
|
||||||
banner_message = "Message Node?\nBack\nNew Preset Msg\nNew Freetext Msg";
|
static const char *optionsArray[] = {"Back", "New Preset Msg", "New Freetext Msg"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 3;
|
options = 3;
|
||||||
} else {
|
} else {
|
||||||
banner_message = "Message Node?\nBack\nNew Preset Msg";
|
static const char *optionsArray[] = {"Back", "New Preset Msg"};
|
||||||
|
optionsArrayPtr = optionsArray;
|
||||||
options = 2;
|
options = 2;
|
||||||
}
|
}
|
||||||
showOverlayBanner(banner_message, 30000, options, [](int selected) -> void {
|
showOverlayBanner("Message Node?", 30000, optionsArrayPtr, options, [](int selected) -> void {
|
||||||
if (selected == 1) {
|
if (selected == 1) {
|
||||||
cannedMessageModule->LaunchWithDestination(graphics::UIRenderer::currentFavoriteNodeNum);
|
cannedMessageModule->LaunchWithDestination(graphics::UIRenderer::currentFavoriteNodeNum);
|
||||||
} else if (selected == 2) {
|
} else if (selected == 2) {
|
||||||
@ -1404,12 +1430,33 @@ bool Screen::isOverlayBannerShowing()
|
|||||||
|
|
||||||
void Screen::LoraRegionPicker(uint32_t duration)
|
void Screen::LoraRegionPicker(uint32_t duration)
|
||||||
{
|
{
|
||||||
|
static const char *optionsArray[] = {"Back",
|
||||||
|
"US",
|
||||||
|
"EU_433",
|
||||||
|
"EU_868",
|
||||||
|
"CN",
|
||||||
|
"JP",
|
||||||
|
"ANZ",
|
||||||
|
"KR",
|
||||||
|
"TW",
|
||||||
|
"RU",
|
||||||
|
"IN",
|
||||||
|
"NZ_865",
|
||||||
|
"TH",
|
||||||
|
"LORA_24",
|
||||||
|
"UA_433",
|
||||||
|
"UA_868",
|
||||||
|
"MY_433",
|
||||||
|
"MY_"
|
||||||
|
"919",
|
||||||
|
"SG_"
|
||||||
|
"923",
|
||||||
|
"PH_433",
|
||||||
|
"PH_868",
|
||||||
|
"PH_915",
|
||||||
|
"ANZ_433"};
|
||||||
showOverlayBanner(
|
showOverlayBanner(
|
||||||
"Set the LoRa "
|
"Set the LoRa region", duration, optionsArray, 23,
|
||||||
"region\nBack\nUS\nEU_433\nEU_868\nCN\nJP\nANZ\nKR\nTW\nRU\nIN\nNZ_865\nTH\nLORA_24\nUA_433\nUA_868\nMY_433\nMY_"
|
|
||||||
"919\nSG_"
|
|
||||||
"923\nPH_433\nPH_868\nPH_915\nANZ_433",
|
|
||||||
duration, 23,
|
|
||||||
[](int selected) -> void {
|
[](int selected) -> void {
|
||||||
if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) {
|
if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) {
|
||||||
config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected);
|
config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected);
|
||||||
@ -1445,51 +1492,98 @@ void Screen::LoraRegionPicker(uint32_t duration)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Screen::TwelveHourPicker()
|
||||||
|
{
|
||||||
|
static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
|
||||||
|
showOverlayBanner("Pick Timezone", 30000, optionsArray, 3, [](int selected) -> void {
|
||||||
|
if (selected == 0) {
|
||||||
|
return;
|
||||||
|
} else if (selected == 1) {
|
||||||
|
config.display.use_12h_clock = true;
|
||||||
|
} else {
|
||||||
|
config.display.use_12h_clock = false;
|
||||||
|
}
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Screen::TZPicker()
|
void Screen::TZPicker()
|
||||||
{
|
{
|
||||||
showOverlayBanner(
|
static const char *optionsArray[] = {"Back",
|
||||||
"Pick "
|
"US/Hawaii",
|
||||||
"Timezone\nBack\nUS/Hawaii\nUS/Alaska\nUS/Pacific\nUS/Mountain\nUS/Central\nUS/Eastern\nUTC\nEU/Western\nEU/"
|
"US/Alaska",
|
||||||
"Central\nEU/Eastern\nAsia/Kolkata\nAsia/Hong_Kong\nAU/AWST\nAU/ACST\nAU/AEST\nPacific/NZ",
|
"US/Pacific",
|
||||||
30000, 17, [](int selected) -> void {
|
"US/Mountain",
|
||||||
if (selected == 1) { // Hawaii
|
"US/Central",
|
||||||
strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef));
|
"US/Eastern",
|
||||||
} else if (selected == 2) { // Alaska
|
"UTC",
|
||||||
strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
"EU/Western",
|
||||||
} else if (selected == 3) { // Pacific
|
"EU/"
|
||||||
strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
"Central",
|
||||||
} else if (selected == 4) { // Mountain
|
"EU/Eastern",
|
||||||
strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
"Asia/Kolkata",
|
||||||
} else if (selected == 5) { // Central
|
"Asia/Hong_Kong",
|
||||||
strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
"AU/AWST",
|
||||||
} else if (selected == 6) { // Eastern
|
"AU/ACST",
|
||||||
strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
"AU/AEST",
|
||||||
} else if (selected == 7) { // UTC
|
"Pacific/NZ"};
|
||||||
strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef));
|
showOverlayBanner("Pick Timezone", 30000, optionsArray, 17, [](int selected) -> void {
|
||||||
} else if (selected == 8) { // EU/Western
|
if (selected == 1) { // Hawaii
|
||||||
strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 9) { // EU/Central
|
} else if (selected == 2) { // Alaska
|
||||||
strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 10) { // EU/Eastern
|
} else if (selected == 3) { // Pacific
|
||||||
strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 11) { // Asia/Kolkata
|
} else if (selected == 4) { // Mountain
|
||||||
strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 12) { // China
|
} else if (selected == 5) { // Central
|
||||||
strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 13) { // AU/AWST
|
} else if (selected == 6) { // Eastern
|
||||||
strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 14) { // AU/ACST
|
} else if (selected == 7) { // UTC
|
||||||
strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 15) { // AU/AEST
|
} else if (selected == 8) { // EU/Western
|
||||||
strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef));
|
||||||
} else if (selected == 16) { // NZ
|
} else if (selected == 9) { // EU/Central
|
||||||
strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef));
|
strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef));
|
||||||
}
|
} else if (selected == 10) { // EU/Eastern
|
||||||
if (selected != 0) {
|
strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef));
|
||||||
setenv("TZ", config.device.tzdef, 1);
|
} else if (selected == 11) { // Asia/Kolkata
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef));
|
||||||
}
|
} else if (selected == 12) { // China
|
||||||
});
|
strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef));
|
||||||
|
} else if (selected == 13) { // AU/AWST
|
||||||
|
strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef));
|
||||||
|
} else if (selected == 14) { // AU/ACST
|
||||||
|
strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
|
||||||
|
} else if (selected == 15) { // AU/AEST
|
||||||
|
strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
|
||||||
|
} else if (selected == 16) { // NZ
|
||||||
|
strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef));
|
||||||
|
}
|
||||||
|
if (selected != 0) {
|
||||||
|
setenv("TZ", config.device.tzdef, 1);
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::handleMenuSwitch()
|
||||||
|
{
|
||||||
|
switch (menuQueue) {
|
||||||
|
case menu_none:
|
||||||
|
break;
|
||||||
|
case lora_picker:
|
||||||
|
LoraRegionPicker();
|
||||||
|
break;
|
||||||
|
case TZ_picker:
|
||||||
|
TZPicker();
|
||||||
|
break;
|
||||||
|
case twelve_hour_picker:
|
||||||
|
TwelveHourPicker();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
menuQueue = menu_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
@ -201,6 +201,9 @@ class Screen : public concurrency::OSThread
|
|||||||
size_t frameCount = 0; // Total number of active frames
|
size_t frameCount = 0; // Total number of active frames
|
||||||
~Screen();
|
~Screen();
|
||||||
|
|
||||||
|
enum screenMenus { menu_none, lora_picker, TZ_picker, twelve_hour_picker };
|
||||||
|
screenMenus menuQueue = menu_none;
|
||||||
|
|
||||||
// Which frame we want to be displayed, after we regen the frameset by calling setFrames
|
// Which frame we want to be displayed, after we regen the frameset by calling setFrames
|
||||||
enum FrameFocus : uint8_t {
|
enum FrameFocus : uint8_t {
|
||||||
FOCUS_DEFAULT, // No specific frame
|
FOCUS_DEFAULT, // No specific frame
|
||||||
@ -285,8 +288,8 @@ class Screen : public concurrency::OSThread
|
|||||||
enqueueCmd(cmd);
|
enqueueCmd(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, uint8_t options = 0,
|
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, const char **optionsArrayPtr = nullptr,
|
||||||
std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0);
|
uint8_t options = 0, std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0);
|
||||||
|
|
||||||
void startFirmwareUpdateScreen()
|
void startFirmwareUpdateScreen()
|
||||||
{
|
{
|
||||||
@ -601,7 +604,9 @@ class Screen : public concurrency::OSThread
|
|||||||
void handleShowNextFrame();
|
void handleShowNextFrame();
|
||||||
void handleShowPrevFrame();
|
void handleShowPrevFrame();
|
||||||
void handleStartFirmwareUpdateScreen();
|
void handleStartFirmwareUpdateScreen();
|
||||||
|
void handleMenuSwitch();
|
||||||
void TZPicker();
|
void TZPicker();
|
||||||
|
void TwelveHourPicker();
|
||||||
void LoraRegionPicker(uint32_t duration = 30000);
|
void LoraRegionPicker(uint32_t duration = 30000);
|
||||||
|
|
||||||
// Info collected by setFrames method.
|
// Info collected by setFrames method.
|
||||||
|
@ -31,6 +31,7 @@ int8_t NotificationRenderer::curSelected = 0;
|
|||||||
char NotificationRenderer::alertBannerMessage[256] = {0};
|
char NotificationRenderer::alertBannerMessage[256] = {0};
|
||||||
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
|
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
|
||||||
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options
|
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options
|
||||||
|
const char **NotificationRenderer::optionsArrayPtr = nullptr;
|
||||||
std::function<void(int)> NotificationRenderer::alertBannerCallback = NULL;
|
std::function<void(int)> NotificationRenderer::alertBannerCallback = NULL;
|
||||||
bool NotificationRenderer::pauseBanner = false;
|
bool NotificationRenderer::pauseBanner = false;
|
||||||
|
|
||||||
@ -71,20 +72,20 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
// Search the message to determine if we need the bell added
|
// Search the message to determine if we need the bell added
|
||||||
bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
||||||
|
|
||||||
uint8_t firstOption = 0;
|
|
||||||
uint8_t firstOptionToShow = 0;
|
uint8_t firstOptionToShow = 0;
|
||||||
|
|
||||||
// Setup font and alignment
|
// Setup font and alignment
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line
|
display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line
|
||||||
const int MAX_LINES = 24;
|
const int MAX_LINES = 5;
|
||||||
|
uint16_t optionWidths[alertBannerOptions] = {0};
|
||||||
uint16_t maxWidth = 0;
|
uint16_t maxWidth = 0;
|
||||||
uint16_t arrowsWidth = display->getStringWidth("> <", 4, true);
|
uint16_t arrowsWidth = display->getStringWidth("> <", 4, true);
|
||||||
uint16_t lineWidths[MAX_LINES] = {0};
|
uint16_t lineWidths[MAX_LINES] = {0};
|
||||||
uint16_t lineLengths[MAX_LINES] = {0};
|
uint16_t lineLengths[MAX_LINES] = {0};
|
||||||
char *lineStarts[MAX_LINES + 1];
|
char *lineStarts[MAX_LINES + 1];
|
||||||
uint16_t lineCount = 0;
|
uint16_t lineCount = 0;
|
||||||
|
uint16_t totalCount = 0;
|
||||||
char lineBuffer[40] = {0};
|
char lineBuffer[40] = {0};
|
||||||
// pointer to the terminating null
|
// pointer to the terminating null
|
||||||
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
||||||
@ -101,14 +102,22 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
if (lineWidths[lineCount] > maxWidth) {
|
if (lineWidths[lineCount] > maxWidth) {
|
||||||
maxWidth = lineWidths[lineCount];
|
maxWidth = lineWidths[lineCount];
|
||||||
}
|
}
|
||||||
if (alertBannerOptions > 0 && lineCount > 0 && lineWidths[lineCount] + arrowsWidth > maxWidth) {
|
|
||||||
maxWidth = lineWidths[lineCount] + arrowsWidth;
|
|
||||||
}
|
|
||||||
lineCount++;
|
lineCount++;
|
||||||
// if we are doing a selection, add extra width for arrows
|
// if we are doing a selection, add extra width for arrows
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alertBannerOptions > 0) {
|
if (alertBannerOptions > 0) {
|
||||||
|
for (int i = 0; i < alertBannerOptions; i++) {
|
||||||
|
optionWidths[i] = display->getStringWidth(optionsArrayPtr[i], strlen(optionsArrayPtr[i]), true);
|
||||||
|
if (optionWidths[i] > maxWidth) {
|
||||||
|
maxWidth = optionWidths[i];
|
||||||
|
}
|
||||||
|
if (optionWidths[i] + arrowsWidth > maxWidth) {
|
||||||
|
maxWidth = optionWidths[i] + arrowsWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalCount = lineCount + alertBannerOptions;
|
||||||
|
|
||||||
// respond to input
|
// respond to input
|
||||||
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
|
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
|
||||||
curSelected--;
|
curSelected--;
|
||||||
@ -124,15 +133,11 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
curSelected = alertBannerOptions - 1;
|
curSelected = alertBannerOptions - 1;
|
||||||
if (curSelected == alertBannerOptions)
|
if (curSelected == alertBannerOptions)
|
||||||
curSelected = 0;
|
curSelected = 0;
|
||||||
// compare number of options to number of lines
|
|
||||||
if (lineCount < alertBannerOptions)
|
|
||||||
return;
|
|
||||||
firstOption = lineCount - alertBannerOptions;
|
|
||||||
if (curSelected > 1 && alertBannerOptions > 3) {
|
if (curSelected > 1 && alertBannerOptions > 3) {
|
||||||
firstOptionToShow = curSelected + firstOption - 1;
|
firstOptionToShow = curSelected - 1;
|
||||||
// put the selected option in the middle
|
// put the selected option in the middle
|
||||||
} else {
|
} else {
|
||||||
firstOptionToShow = firstOption;
|
firstOptionToShow = 0;
|
||||||
}
|
}
|
||||||
} else { // not in an alert with a callback
|
} else { // not in an alert with a callback
|
||||||
// TODO: check that at least a second has passed since the alert started
|
// TODO: check that at least a second has passed since the alert started
|
||||||
@ -143,7 +148,6 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
inEvent = INPUT_BROKER_NONE;
|
inEvent = INPUT_BROKER_NONE;
|
||||||
if (alertBannerMessage[0] == '\0')
|
if (alertBannerMessage[0] == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// set width from longest line
|
// set width from longest line
|
||||||
uint16_t boxWidth = padding * 2 + maxWidth;
|
uint16_t boxWidth = padding * 2 + maxWidth;
|
||||||
if (needs_bell) {
|
if (needs_bell) {
|
||||||
@ -157,8 +161,8 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
// calculate max lines on screen? for now it's 4
|
// calculate max lines on screen? for now it's 4
|
||||||
// set height from line count
|
// set height from line count
|
||||||
uint16_t boxHeight;
|
uint16_t boxHeight;
|
||||||
if (lineCount <= 4) {
|
if (totalCount <= 4) {
|
||||||
boxHeight = vPadding * 2 + lineCount * FONT_HEIGHT_SMALL + (lineCount - 1) * lineSpacing;
|
boxHeight = vPadding * 2 + totalCount * FONT_HEIGHT_SMALL + (totalCount - 1) * lineSpacing;
|
||||||
} else {
|
} else {
|
||||||
boxHeight = vPadding * 2 + 4 * FONT_HEIGHT_SMALL + 4 * lineSpacing;
|
boxHeight = vPadding * 2 + 4 * FONT_HEIGHT_SMALL + 4 * lineSpacing;
|
||||||
}
|
}
|
||||||
@ -185,37 +189,11 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
int16_t lineY = boxTop + vPadding;
|
int16_t lineY = boxTop + vPadding;
|
||||||
|
|
||||||
for (int i = 0; i < lineCount; i++) {
|
for (int i = 0; i < lineCount; i++) {
|
||||||
// is this line selected?
|
strncpy(lineBuffer, lineStarts[i], 40);
|
||||||
// if so, start the buffer with -> and strncpy to the 4th location
|
if (lineLengths[i] > 39)
|
||||||
if (i < lineCount - alertBannerOptions || alertBannerOptions == 0) {
|
lineBuffer[39] = '\0';
|
||||||
strncpy(lineBuffer, lineStarts[i], 40);
|
else
|
||||||
if (lineLengths[i] > 39)
|
lineBuffer[lineLengths[i]] = '\0';
|
||||||
lineBuffer[39] = '\0';
|
|
||||||
else
|
|
||||||
lineBuffer[lineLengths[i]] = '\0';
|
|
||||||
} else if (i >= firstOptionToShow && i < firstOptionToShow + 3) {
|
|
||||||
if (i == curSelected + firstOption) {
|
|
||||||
if (lineLengths[i] > 35)
|
|
||||||
lineLengths[i] = 35;
|
|
||||||
strncpy(lineBuffer, "> ", 3);
|
|
||||||
strncpy(lineBuffer + 2, lineStarts[i], 36);
|
|
||||||
strncpy(lineBuffer + lineLengths[i] + 2, " <", 3);
|
|
||||||
lineLengths[i] += 4;
|
|
||||||
lineWidths[i] += display->getStringWidth("> <", 4, true);
|
|
||||||
if (lineLengths[i] > 35)
|
|
||||||
lineBuffer[39] = '\0';
|
|
||||||
else
|
|
||||||
lineBuffer[lineLengths[i]] = '\0';
|
|
||||||
} else {
|
|
||||||
strncpy(lineBuffer, lineStarts[i], 40);
|
|
||||||
if (lineLengths[i] > 39)
|
|
||||||
lineBuffer[39] = '\0';
|
|
||||||
else
|
|
||||||
lineBuffer[lineLengths[i]] = '\0';
|
|
||||||
}
|
|
||||||
} else { // add break for the additional lines
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
||||||
|
|
||||||
@ -228,6 +206,34 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
display->drawString(textX, lineY, lineBuffer);
|
display->drawString(textX, lineY, lineBuffer);
|
||||||
lineY += FONT_HEIGHT_SMALL + lineSpacing;
|
lineY += FONT_HEIGHT_SMALL + lineSpacing;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < alertBannerOptions; i++) {
|
||||||
|
// is this line selected?
|
||||||
|
// if so, start the buffer with -> and strncpy to the 4th location
|
||||||
|
if (i >= firstOptionToShow && i < firstOptionToShow + 3) {
|
||||||
|
if (i == curSelected) {
|
||||||
|
strncpy(lineBuffer, "> ", 3);
|
||||||
|
strncpy(lineBuffer + 2, optionsArrayPtr[i], 36);
|
||||||
|
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3);
|
||||||
|
optionWidths[i] += arrowsWidth;
|
||||||
|
lineBuffer[39] = '\0';
|
||||||
|
} else {
|
||||||
|
strncpy(lineBuffer, optionsArrayPtr[i], 40);
|
||||||
|
lineBuffer[39] = '\0';
|
||||||
|
}
|
||||||
|
int16_t textX = boxLeft + (boxWidth - optionWidths[i]) / 2;
|
||||||
|
|
||||||
|
if (needs_bell && i == 0) {
|
||||||
|
int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
|
||||||
|
display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
|
||||||
|
display->drawXbm(textX + optionWidths[i] + 2, bellY, 8, 8, bell_alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
display->drawString(textX, lineY, lineBuffer);
|
||||||
|
lineY += FONT_HEIGHT_SMALL + lineSpacing;
|
||||||
|
} else { // add break for the additional lines
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
|
@ -12,7 +12,8 @@ class NotificationRenderer
|
|||||||
static char inEvent;
|
static char inEvent;
|
||||||
static int8_t curSelected;
|
static int8_t curSelected;
|
||||||
static char alertBannerMessage[256];
|
static char alertBannerMessage[256];
|
||||||
static uint32_t alertBannerUntil; // 0 is a special case meaning forever
|
static uint32_t alertBannerUntil; // 0 is a special case meaning forever
|
||||||
|
static const char **optionsArrayPtr;
|
||||||
static uint8_t alertBannerOptions; // last x lines are seelctable options
|
static uint8_t alertBannerOptions; // last x lines are seelctable options
|
||||||
static std::function<void(int)> alertBannerCallback;
|
static std::function<void(int)> alertBannerCallback;
|
||||||
|
|
||||||
|
@ -79,10 +79,10 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
|||||||
memset(message, 0, sizeof(message));
|
memset(message, 0, sizeof(message));
|
||||||
sprintf(message, "Verification: \n");
|
sprintf(message, "Verification: \n");
|
||||||
generateVerificationCode(message + 15);
|
generateVerificationCode(message + 15);
|
||||||
sprintf(message + 24, "\nACCEPT\nREJECT");
|
static const char *optionsArray[] = {"ACCEPT", "REJECT"};
|
||||||
LOG_INFO("Hash1 matches!");
|
LOG_INFO("Hash1 matches!");
|
||||||
if (screen) {
|
if (screen) {
|
||||||
screen->showOverlayBanner(message, 30000, 2, [=](int selected) {
|
screen->showOverlayBanner(message, 30000, optionsArray, 2, [=](int selected) {
|
||||||
if (selected == 0) {
|
if (selected == 0) {
|
||||||
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
|
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
|
||||||
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||||
|
Loading…
Reference in New Issue
Block a user