#include #include "shared_context.h" #include "ui_callbacks.h" #include "ui_nbgl.h" #include "sign_message.h" #include "glyphs.h" #include "nbgl_use_case.h" #include "common_ui.h" typedef enum { UI_191_NBGL_START_REVIEW_DISPLAYED = 0, UI_191_NBGL_GO_TO_NEXT_CONTENT, UI_191_NBGL_BACK_FROM_REJECT_CANCEL, UI_191_NBGL_GO_TO_SIGN, UI_191_NBGL_SIGN_DISPLAYED, } e_ui_nbgl_191_state; static e_ui_nbgl_191_state state; static e_ui_nbgl_191_state state_before_reject_cancel; static bool skip_message; static nbgl_layoutTagValue_t pair; // static uint32_t eip191MessageIdx = 0; static uint32_t stringsTmpTmpIdx = 0; static void reject_message(void) { io_seproxyhal_touch_signMessage_cancel(); } static void sign_message(void) { io_seproxyhal_touch_signMessage_ok(); } static bool display_message(nbgl_pageContent_t *content) { uint16_t len = 0; bool reached; if (state != UI_191_NBGL_BACK_FROM_REJECT_CANCEL) { strncpy(staxSharedBuffer + eip191MessageIdx, strings.tmp.tmp + stringsTmpTmpIdx, SHARED_BUFFER_SIZE - eip191MessageIdx); reached = nbgl_getTextMaxLenInNbLines(BAGL_FONT_INTER_REGULAR_32px, (char *) staxSharedBuffer, SCREEN_WIDTH - (2 * BORDER_MARGIN), 9, &len); stringsTmpTmpIdx = len - eip191MessageIdx; eip191MessageIdx = len; staxSharedBuffer[eip191MessageIdx] = '\0'; if (!reached && eip191MessageIdx < SHARED_BUFFER_SIZE) { stringsTmpTmpIdx = 0; question_switcher(); if (state != UI_191_NBGL_GO_TO_SIGN) { return false; } } else if (reached || eip191MessageIdx == SHARED_BUFFER_SIZE) { eip191MessageIdx = 0; } } pair.value = staxSharedBuffer; pair.item = "Message"; content->type = TAG_VALUE_LIST; content->tagValueList.nbPairs = 1; content->tagValueList.pairs = &pair; content->tagValueList.smallCaseForValue = false; content->tagValueList.nbMaxLinesForValue = 9; content->tagValueList.wrapping = false; if (state == UI_191_NBGL_BACK_FROM_REJECT_CANCEL) { // We come back from Reject screen. // The previously displayed content must be redisplayed. // Do not call question_switcher() to avoid replacing // string.tmp.tmp content. state = state_before_reject_cancel; } else if (stringsTmpTmpIdx >= strlen(strings.tmp.tmp)) { // Fetch the next content to display into strings.tmp.tmp buffer. stringsTmpTmpIdx = 0; question_switcher(); } return true; } static void display_sign(nbgl_pageContent_t *content) { content->type = INFO_LONG_PRESS, content->infoLongPress.icon = &C_Message_64px; content->infoLongPress.text = "Sign Message?"; content->infoLongPress.longPressText = "Hold to sign"; state = UI_191_NBGL_SIGN_DISPLAYED; } static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { bool ret = true; if (page == LAST_PAGE_FOR_REVIEW) { // was skipped skip_message = true; skip_rest_of_message(); } if ((state != UI_191_NBGL_GO_TO_SIGN) && (state != UI_191_NBGL_SIGN_DISPLAYED)) { if (skip_message) { // do not refresh when this callback triggers after user validation ret = false; } else { ret = display_message(content); } } else { // the last page must contain a long press button display_sign(content); } return ret; } static void choice_callback(bool confirm) { if (confirm) { nbgl_useCaseStatus("MESSAGE\nSIGNED", true, sign_message); sign_message(); } } static void continue_review(void) { nbgl_useCaseForwardOnlyReview("Reject", NULL, nav_callback, choice_callback); } static void confirm_transaction_rejection_choice(bool confirm) { if (confirm) { reject_message(); } else { // Go to previous screen accordingly if (state == UI_191_NBGL_START_REVIEW_DISPLAYED) { ui_191_start(); } else { if (state != UI_191_NBGL_SIGN_DISPLAYED) { state_before_reject_cancel = state; state = UI_191_NBGL_BACK_FROM_REJECT_CANCEL; } continue_review(); } } } static void confirm_transaction_rejection() { nbgl_useCaseChoice(&C_warning64px, "Reject message?", NULL, "Yes, Reject", "Go back to message", confirm_transaction_rejection_choice); } void ui_191_start(void) { state = UI_191_NBGL_START_REVIEW_DISPLAYED; skip_message = false; eip191MessageIdx = 0; stringsTmpTmpIdx = 0; nbgl_useCaseReviewStart(&C_Message_64px, "Review message", NULL, "Reject", continue_review, confirm_transaction_rejection); } void ui_191_switch_to_message(void) { // No question mechanism on Stax: // Message is already displayed state = UI_191_NBGL_GO_TO_NEXT_CONTENT; continue_review(); } void ui_191_switch_to_sign(void) { // Next nav_callback callback must display // the hold to approve screen state = UI_191_NBGL_GO_TO_SIGN; if (skip_message) { continue_review(); // to force screen refresh } } void ui_191_switch_to_question(void) { // No question mechanism on Stax: // Always display the next message chunk. continue_displaying_message(); }