mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-05 21:24:34 +00:00
Added destination change on Cannedmessage screen and dismiss text message frame on reply.
This commit is contained in:
parent
b35fb886e4
commit
2432d0616b
@ -69,7 +69,7 @@ CannedMessageModule::CannedMessageModule()
|
|||||||
disable();
|
disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static bool returnToCannedList = false;
|
||||||
bool hasKeyForNode(const meshtastic_NodeInfoLite* node) {
|
bool hasKeyForNode(const meshtastic_NodeInfoLite* node) {
|
||||||
return node && node->has_user && node->user.public_key.size > 0;
|
return node && node->has_user && node->user.public_key.size > 0;
|
||||||
}
|
}
|
||||||
@ -116,16 +116,19 @@ int CannedMessageModule::splitConfiguredMessages()
|
|||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add "[Select Destination]" as the final message
|
||||||
if (strlen(this->messages[messageIndex - 1]) > 0) {
|
if (strlen(this->messages[messageIndex - 1]) > 0) {
|
||||||
// We have a last message.
|
this->messages[messageIndex - 1] = (char*)"[Select Destination]";
|
||||||
LOG_DEBUG("CannedMessage %d is: '%s'", messageIndex - 1, this->messages[messageIndex - 1]);
|
|
||||||
this->messagesCount = messageIndex;
|
this->messagesCount = messageIndex;
|
||||||
} else {
|
} else {
|
||||||
this->messagesCount = messageIndex - 1;
|
this->messages[messageIndex - 1] = (char*)"[Select Destination]";
|
||||||
|
this->messagesCount = messageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->messagesCount;
|
return this->messagesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CannedMessageModule::resetSearch() {
|
void CannedMessageModule::resetSearch() {
|
||||||
LOG_INFO("Resetting search, restoring full destination list");
|
LOG_INFO("Resetting search, restoring full destination list");
|
||||||
|
|
||||||
@ -340,7 +343,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✅ Now correctly switches to FreeText screen with selected node/channel
|
// ✅ Now correctly switches to FreeText screen with selected node/channel
|
||||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
this->runState = returnToCannedList ? CANNED_MESSAGE_RUN_STATE_ACTIVE : CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||||
|
returnToCannedList = false;
|
||||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||||
screen->forceDisplay();
|
screen->forceDisplay();
|
||||||
return 0;
|
return 0;
|
||||||
@ -381,6 +385,15 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
|
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
|
||||||
|
|
||||||
|
if (strcmp(this->messages[this->currentMessageIndex], "[Select Destination]") == 0) {
|
||||||
|
returnToCannedList = true;
|
||||||
|
this->runState = CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION;
|
||||||
|
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||||
|
this->destIndex = 0;
|
||||||
|
this->scrollIndex = 0;
|
||||||
|
screen->forceDisplay();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#if defined(USE_VIRTUAL_KEYBOARD)
|
#if defined(USE_VIRTUAL_KEYBOARD)
|
||||||
if (this->currentMessageIndex == 0) {
|
if (this->currentMessageIndex == 0) {
|
||||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||||
@ -689,13 +702,22 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
|
|||||||
// Prevents the canned message module from regenerating the screen's frameset at unexpected times,
|
// Prevents the canned message module from regenerating the screen's frameset at unexpected times,
|
||||||
// or raising a UIFrameEvent before another module has the chance
|
// or raising a UIFrameEvent before another module has the chance
|
||||||
this->waitingForAck = true;
|
this->waitingForAck = true;
|
||||||
this->lastSentNode = dest;
|
|
||||||
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||||
|
|
||||||
service->sendToMesh(
|
service->sendToMesh(
|
||||||
p, RX_SRC_LOCAL,
|
p, RX_SRC_LOCAL,
|
||||||
true); // send to mesh, cc to phone. Even if there's no phone connected, this stores the message to match ACKs
|
true); // send to mesh, cc to phone. Even if there's no phone connected, this stores the message to match ACKs
|
||||||
|
|
||||||
|
// === Simulate local message to dismiss the message frame after sending ===
|
||||||
|
// This mimics what happens when replying from the phone to clear unread state and UI
|
||||||
|
if (screen) {
|
||||||
|
meshtastic_MeshPacket simulatedPacket = {};
|
||||||
|
simulatedPacket.from = 0; // Outgoing message (from local device)
|
||||||
|
screen->handleTextMessage(&simulatedPacket); // Calls logic to clear unread and dismiss frame
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long lastUpdateMillis = 0;
|
unsigned long lastUpdateMillis = 0;
|
||||||
int32_t CannedMessageModule::runOnce()
|
int32_t CannedMessageModule::runOnce()
|
||||||
{
|
{
|
||||||
@ -752,6 +774,10 @@ int32_t CannedMessageModule::runOnce()
|
|||||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (strcmp(this->messages[this->currentMessageIndex], "[Select Destination]") == 0) {
|
||||||
|
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||||
|
return INT32_MAX;
|
||||||
|
}
|
||||||
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
|
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
|
||||||
if (strcmp(this->messages[this->currentMessageIndex], "~") == 0) {
|
if (strcmp(this->messages[this->currentMessageIndex], "~") == 0) {
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
@ -1384,18 +1410,8 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
|||||||
#else
|
#else
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
#endif
|
#endif
|
||||||
if (this->ack) {
|
String displayString = this->ack ? "Delivered to\n%s" : "Delivery failed\nto %s";
|
||||||
if (this->lastSentNode == NODENUM_BROADCAST) {
|
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, displayString, getNodeName(this->incoming));
|
||||||
snprintf(buffer, sizeof(buffer), "Relayed to %s", channels.getName(this->channel));
|
|
||||||
} else {
|
|
||||||
snprintf(buffer, sizeof(buffer), "%s\nto %s",
|
|
||||||
this->lastAckWasRelayed ? "Delivered (Relayed)" : "Delivered (Direct)",
|
|
||||||
getNodeName(this->incoming));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(buffer, sizeof(buffer), "Delivery failed\nto %s", getNodeName(this->incoming));
|
|
||||||
}
|
|
||||||
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, buffer);
|
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// SNR/RSSI
|
// SNR/RSSI
|
||||||
@ -1520,43 +1536,22 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //! HAS_TFT
|
#endif
|
||||||
|
|
||||||
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) {
|
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) {
|
||||||
|
// look for a request_id
|
||||||
if (mp.decoded.request_id != 0) {
|
if (mp.decoded.request_id != 0) {
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
|
||||||
requestFocus();
|
requestFocus(); // Tell Screen::setFrames that our module's frame should be shown, even if not "first" in the frameset
|
||||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
|
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
|
||||||
|
this->incoming = service->getNodenumFromRequestId(mp.decoded.request_id);
|
||||||
// Decode the Routing payload to check for errors
|
|
||||||
meshtastic_Routing decoded = meshtastic_Routing_init_default;
|
meshtastic_Routing decoded = meshtastic_Routing_init_default;
|
||||||
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
|
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
|
||||||
|
this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE;
|
||||||
// === Relay Detection ===
|
waitingForAck = false; // No longer want routing packets
|
||||||
uint8_t relayByte = mp.relay_node;
|
|
||||||
uint8_t senderLastByte = mp.from & 0xFF;
|
|
||||||
this->lastAckWasRelayed = (relayByte != senderLastByte);
|
|
||||||
|
|
||||||
// === Accept ACK if no error AND:
|
|
||||||
// - Broadcast (allow any ACK)
|
|
||||||
// - OR matches exact destination
|
|
||||||
bool isAck = (decoded.error_reason == meshtastic_Routing_Error_NONE);
|
|
||||||
bool isFromDest = (mp.from == this->lastSentNode);
|
|
||||||
bool isBroadcast = (this->lastSentNode == NODENUM_BROADCAST);
|
|
||||||
|
|
||||||
this->ack = isAck && (isBroadcast || isFromDest);
|
|
||||||
|
|
||||||
// === Set .incoming to the node who ACK'd (even if it was broadcast)
|
|
||||||
if (isBroadcast && mp.from != nodeDB->getNodeNum()) {
|
|
||||||
this->incoming = mp.from;
|
|
||||||
} else {
|
|
||||||
this->incoming = this->lastSentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
waitingForAck = false;
|
|
||||||
this->notifyObservers(&e);
|
this->notifyObservers(&e);
|
||||||
// run the next time 2 seconds later
|
// run the next time 2 seconds later
|
||||||
setIntervalFromNow(2000);
|
setIntervalFromNow(2000);
|
||||||
|
Loading…
Reference in New Issue
Block a user