16#include "os_io_seph_ux.h"
19#include "os_helpers.h"
26#define PAGE_NB_ELEMENTS_BITS 3
27#define GET_PAGE_NB_ELEMENTS(pageData) ((pageData) &0x07)
28#define SET_PAGE_NB_ELEMENTS(nbElements) ((nbElements) &0x07)
30#define PAGE_FLAG_BITS 1
31#define GET_PAGE_FLAG(pageData) (((pageData) &0x08) >> 3)
32#define SET_PAGE_FLAG(flag) (((flag) &0x01) << 3)
34#define PAGE_DATA_BITS (PAGE_NB_ELEMENTS_BITS + PAGE_FLAG_BITS)
35#define PAGES_PER_UINT8 (8 / PAGE_DATA_BITS)
36#define SET_PAGE_DATA(pageIdx, pageData) \
37 (pagesData[pageIdx / PAGES_PER_UINT8] = pageData \
38 << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS))
40#define MAX_PAGE_NB 256
41#define MAX_MODAL_PAGE_NB 32
44#define STARTING_CONTENT localContentsList[0]
45#define FINISHING_CONTENT localContentsList[1]
48#define QRCODE_NB_MAX_LINES 3
50#define QRCODE_REDUCED_ADDR_LEN 128
53#define ADDR_VERIF_NB_PAIRS 3
56#define sharedContext genericContext.sharedCtx
57#define keypadContext sharedContext.keypad
58#define keyboardContext sharedContext.keyboard
59#define reviewWithWarnCtx sharedContext.reviewWithWarning
60#define choiceWithDetailsCtx sharedContext.choiceWithDetails
63#define W3C_DESCRIPTION_MAX_LEN 128
76 ADDRESS_QRCODE_BUTTON_TOKEN,
89 QUIT_TIPBOX_MODAL_TOKEN,
92 DISMISS_WARNING_TOKEN,
93 DISMISS_DETAILS_TOKEN,
95 KEYBOARD_BUTTON_TOKEN,
109typedef struct DetailsContext_s {
112 uint8_t currentPairIdx;
116 const char *nextPageStart;
119typedef struct AddressConfirmationContext_s {
123} AddressConfirmationContext_t;
126typedef struct KeypadContext_s {
129 uint8_t pinMinDigits;
130 uint8_t pinMaxDigits;
138typedef struct KeyboardContext_s {
149typedef struct ReviewWithWarningContext_s {
154 const char *reviewTitle;
155 const char *reviewSubTitle;
156 const char *finishTitle;
161 uint8_t securityReportLevel;
163} ReviewWithWarningContext_t;
165typedef struct ChoiceWithDetailsContext_s {
170} ChoiceWithDetailsContext_t;
174 SHARE_CTX_REVIEW_WITH_WARNING,
175 SHARE_CTX_CHOICE_WITH_DETAILS,
176} SharedContextUsage_t;
183 KeypadContext_t keypad;
186 KeyboardContext_t keyboard;
188 ReviewWithWarningContext_t reviewWithWarning;
189 ChoiceWithDetailsContext_t choiceWithDetails;
191 SharedContextUsage_t usage;
195 USE_CASE_GENERIC = 0,
197} GenericContextType_t;
200 GenericContextType_t type;
201 uint8_t spinnerPosition;
203 int8_t currentContentIdx;
204 uint8_t currentContentElementNb;
205 uint8_t currentElementIdx;
206 bool hasStartingContent;
207 bool hasFinishingContent;
208 const char *detailsItem;
209 const char *detailsvalue;
210 bool detailsWrapping;
211 bool validWarningCtx;
221 SharedContext_t sharedCtx;
232} nbgl_homeAndSettingsContext_t;
237} nbgl_reviewContext_t;
245} nbgl_reviewStreamingContext_t;
248 nbgl_homeAndSettingsContext_t homeAndSettings;
249 nbgl_reviewContext_t review;
250 nbgl_reviewStreamingContext_t reviewStreaming;
251} nbgl_BundleNavContext_t;
257} SecurityReportItem_t;
264static char tmpString[W3C_DESCRIPTION_MAX_LEN];
281static const char *pageTitle;
284#define activeTipBox genericContext.tipBox
288static bool forwardNavOnly;
289static NavType_t navType;
291static DetailsContext_t detailsContext;
294static AddressConfirmationContext_t addressConfirmationContext;
297static GenericContext_t genericContext;
299 localContentsList[3];
300static uint8_t genericContextPagesInfo[MAX_PAGE_NB / PAGES_PER_UINT8];
301static uint8_t modalContextPagesInfo[MAX_MODAL_PAGE_NB / PAGES_PER_UINT8];
304static nbgl_BundleNavContext_t bundleNavContext;
307static const uint8_t nbMaxElementsPerContentType[] = {
325 .text =
"Blind signing required",
326 .subText =
"This transaction's details are not fully verifiable. If "
327 "you sign, you could lose all your assets."
331 .text =
"Transaction Check unavailable",
336 .text =
"Risk detected",
337 .subText =
"This transaction was scanned as risky by Web3 Checks."
341 .text =
"Critical threat",
342 .subText =
"This transaction was scanned as malicious by Web3 Checks."
346 .text =
"No threat detected",
347 .subText =
"Transaction Check didn't find any threat, but always "
348 "review transaction details carefully."
358static char reducedAddress[QRCODE_REDUCED_ADDR_LEN];
364static void displayReviewPage(uint8_t page,
bool forceFullRefresh);
365static void displayDetailsPage(uint8_t page,
bool forceFullRefresh);
366static void displayTagValueListModalPage(uint8_t pageIdx,
bool forceFullRefresh);
367static void displayFullValuePage(
const char *backText,
368 const char *aliasText,
370static void displayInfosListModal(
const char *modalTitle,
374static void displaySettingsPage(uint8_t page,
bool forceFullRefresh);
375static void displayGenericContextPage(uint8_t pageIdx,
bool forceFullRefresh);
376static void pageCallback(
int token, uint8_t index);
378static void displayAddressQRCode(
void);
380static void modalLayoutTouchCallback(
int token, uint8_t index);
381static void displaySkipWarning(
void);
383static void bundleNavStartHome(
void);
384static void bundleNavStartSettingsAtPage(uint8_t initSettingPage);
385static void bundleNavStartSettings(
void);
387static void bundleNavReviewStreamingChoice(
bool confirm);
389static void displaySecurityReport(uint32_t set);
391static void displayInitialWarning(
void);
395 const char *reviewTitle,
396 const char *reviewSubTitle,
397 const char *finishTitle,
401 bool playNotifSound);
404 const char *reviewTitle,
405 const char *reviewSubTitle,
407 bool playNotifSound);
408static void useCaseHomeExt(
const char *appName,
415static void displayDetails(
const char *tag,
const char *value,
bool wrapping);
417static void reset_callbacks_and_context(
void)
424 onContentAction = NULL;
426 memset(&genericContext, 0,
sizeof(genericContext));
430static void genericContextSetPageInfo(uint8_t pageIdx, uint8_t nbElements,
bool flag)
432 uint8_t pageData = SET_PAGE_NB_ELEMENTS(nbElements) + SET_PAGE_FLAG(flag);
434 genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
435 &= ~(0x0F << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS));
436 genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
437 |= pageData << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
441static void genericContextGetPageInfo(uint8_t pageIdx, uint8_t *nbElements,
bool *flag)
443 uint8_t pageData = genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
444 >> ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
445 if (nbElements != NULL) {
446 *nbElements = GET_PAGE_NB_ELEMENTS(pageData);
449 *flag = GET_PAGE_FLAG(pageData);
454static void modalContextSetPageInfo(uint8_t pageIdx, uint8_t nbElements)
456 uint8_t pageData = SET_PAGE_NB_ELEMENTS(nbElements);
458 modalContextPagesInfo[pageIdx / PAGES_PER_UINT8]
459 &= ~(0x0F << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS));
460 modalContextPagesInfo[pageIdx / PAGES_PER_UINT8]
461 |= pageData << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
465static void modalContextGetPageInfo(uint8_t pageIdx, uint8_t *nbElements)
467 uint8_t pageData = modalContextPagesInfo[pageIdx / PAGES_PER_UINT8]
468 >> ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
469 if (nbElements != NULL) {
470 *nbElements = GET_PAGE_NB_ELEMENTS(pageData);
477 switch (content->
type) {
501 if (contentIdx < 0 || contentIdx >= genericContents->
nbContents) {
518static void prepareNavInfo(
bool isReview, uint8_t nbPages,
const char *rejectText)
520 memset(&navInfo, 0,
sizeof(navInfo));
523 navInfo.
tuneId = TUNE_TAP_CASUAL;
527 if (isReview ==
false) {
536 = ((navType == STREAMING_NAV) && (nbPages < 2)) ?
false : true;
543 const char *reviewTitle,
544 const char *reviewSubTitle)
546 contentCenter->
icon = icon;
547 contentCenter->
title = reviewTitle;
549 contentCenter->
subText =
"Swipe to review";
552 contentCenter->
padding =
false;
558 if (finishTitle != NULL) {
563 return "Sign transaction";
565 return "Sign message";
567 return "Sign operation";
574 const char *finishTitle)
576 infoLongPress->
text = getFinishTitle(operationType, finishTitle);
577 infoLongPress->
icon = icon;
585 const char *finishTitle)
587 infoButton->
text = getFinishTitle(operationType, finishTitle);
588 infoButton->
icon = icon;
608static void pageModalCallback(
int token, uint8_t index)
612 if (token == INFOS_TIP_BOX_TOKEN) {
614 displayFullValuePage(activeTipBox.infos.infoTypes[index],
615 activeTipBox.infos.infoContents[index],
616 &activeTipBox.infos.infoExtensions[index]);
619 else if (token == INFO_ALIAS_TOKEN) {
621 displayFullValuePage(genericContext.currentInfos->infoTypes[index],
622 genericContext.currentInfos->infoContents[index],
623 &genericContext.currentInfos->infoExtensions[index]);
627 modalPageContext = NULL;
628 if (token == NAV_TOKEN) {
629 if (index == EXIT_PAGE) {
635 displayDetailsPage(index,
false);
638 if (token == MODAL_NAV_TOKEN) {
639 if (index == EXIT_PAGE) {
645 displayTagValueListModalPage(index,
false);
648 else if (token == QUIT_TOKEN) {
653 else if (token == QUIT_TIPBOX_MODAL_TOKEN) {
655 if (reviewWithWarnCtx.securityReportLevel == 2) {
656 reviewWithWarnCtx.securityReportLevel = 1;
657 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
665 else if (token == SKIP_TOKEN) {
676 else if (token == CHOICE_TOKEN) {
678 if (onModalConfirm != NULL) {
680 onModalConfirm = NULL;
692static void pageCallback(
int token, uint8_t index)
695 if (token == QUIT_TOKEN) {
696 if (onQuit != NULL) {
700 else if (token == CONTINUE_TOKEN) {
701 if (onContinue != NULL) {
705 else if (token == CHOICE_TOKEN) {
706 if (onChoice != NULL) {
707 onChoice((index == 0) ?
true : false);
710 else if (token == ACTION_BUTTON_TOKEN) {
711 if ((index == 0) && (onAction != NULL)) {
714 else if ((index == 1) && (onQuit != NULL)) {
719 else if (token == ADDRESS_QRCODE_BUTTON_TOKEN) {
720 displayAddressQRCode();
723 else if (token == CONFIRM_TOKEN) {
724 if (onChoice != NULL) {
728 else if (token == REJECT_TOKEN) {
729 if (onChoice != NULL) {
733 else if (token == DETAILS_BUTTON_TOKEN) {
734 displayDetails(genericContext.detailsItem,
735 genericContext.detailsvalue,
736 genericContext.detailsWrapping);
738 else if (token == NAV_TOKEN) {
739 if (index == EXIT_PAGE) {
740 if (onQuit != NULL) {
745 if (navType == GENERIC_NAV || navType == STREAMING_NAV) {
746 displayGenericContextPage(index,
false);
748 else if (navType == REVIEW_NAV) {
749 displayReviewPage(index,
false);
752 displaySettingsPage(index,
false);
756 else if (token == NEXT_TOKEN) {
758 displayReviewPage(navInfo.
activePage + 1,
false);
761 displayGenericContextPage(navInfo.
activePage + 1,
false);
764 else if (token == BACK_TOKEN) {
766 displayReviewPage(navInfo.
activePage - 1,
true);
769 displayGenericContextPage(navInfo.
activePage - 1,
false);
772 else if (token == SKIP_TOKEN) {
774 displaySkipWarning();
776 else if (token == VALUE_ALIAS_TOKEN) {
779 if (genericContext.currentPairs != NULL) {
780 pair = &genericContext.currentPairs[genericContext.currentElementIdx + index];
783 pair = genericContext.currentCallback(genericContext.currentElementIdx + index);
787 else if (token == BLIND_WARNING_TOKEN) {
788 reviewWithWarnCtx.isIntro =
false;
789 reviewWithWarnCtx.warning = NULL;
792 else if (token == WARNING_BUTTON_TOKEN) {
794 reviewWithWarnCtx.securityReportLevel = 1;
796 if (reviewWithWarnCtx.warning->predefinedSet) {
797 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
801 if (reviewWithWarnCtx.isIntro) {
802 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->introDetails);
805 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->reviewDetails);
809 else if (token == TIP_BOX_TOKEN) {
811 if (genericContext.validWarningCtx && (reviewWithWarnCtx.warning->predefinedSet != 0)) {
812 reviewWithWarnCtx.securityReportLevel = 1;
813 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
816 displayInfosListModal(activeTipBox.modalTitle, &activeTipBox.infos,
false);
820 if (onContentAction != NULL) {
821 onContentAction(token, index, navInfo.
activePage);
823 if (onControls != NULL) {
824 onControls(token, index);
830static void tickerCallback(
void)
833 if (onQuit != NULL) {
839static void displaySettingsPage(uint8_t page,
bool forceFullRefresh)
847 if (onNav(page, &content) ==
false) {
852 content.
title = pageTitle;
855 content.
tuneId = TUNE_TAP_CASUAL;
860 if (forceFullRefresh) {
869static void displayReviewPage(uint8_t page,
bool forceFullRefresh)
882 if (onNav(navInfo.
activePage, &content) ==
false) {
887 content.
title = NULL;
889 content.
tuneId = TUNE_TAP_CASUAL;
896 if (forwardNavOnly) {
921 if (forceFullRefresh) {
931static const nbgl_content_t *genericContextComputeNextPageParams(uint8_t pageIdx,
933 uint8_t *p_nbElementsInNextPage,
936 int8_t nextContentIdx = genericContext.currentContentIdx;
937 int16_t nextElementIdx = genericContext.currentElementIdx;
938 uint8_t nbElementsInNextPage;
941 genericContextGetPageInfo(pageIdx, &nbElementsInNextPage, p_flag);
942 *p_nbElementsInNextPage = nbElementsInNextPage;
947 uint8_t nbElementsInCurrentPage;
949 genericContextGetPageInfo(navInfo.
activePage, &nbElementsInCurrentPage, NULL);
950 nextElementIdx += nbElementsInCurrentPage;
955 if ((nextElementIdx >= genericContext.currentContentElementNb)
956 && (genericContext.currentContentElementNb > 0)) {
966 nextElementIdx -= nbElementsInNextPage;
972 if (nextElementIdx < 0) {
974 nextElementIdx = -nbElementsInNextPage;
980 if ((nextContentIdx == -1) && (genericContext.hasStartingContent)) {
981 p_content = &STARTING_CONTENT;
983 else if ((nextContentIdx == genericContext.genericContents.nbContents)
984 && (genericContext.hasFinishingContent)) {
985 p_content = &FINISHING_CONTENT;
988 p_content = getContentAtIdx(&genericContext.genericContents, nextContentIdx, content);
990 if (p_content == NULL) {
1005 if ((nextContentIdx != genericContext.currentContentIdx)
1006 || (genericContext.currentContentElementNb == 0)) {
1007 genericContext.currentContentIdx = nextContentIdx;
1008 genericContext.currentContentElementNb = getContentNbElement(p_content);
1010 if (nextElementIdx < 0) {
1011 nextElementIdx = genericContext.currentContentElementNb + nextElementIdx;
1016 if ((nextElementIdx < 0) || (nextElementIdx >= genericContext.currentContentElementNb)) {
1018 "Invalid element index %d / %d\n",
1020 genericContext.currentContentElementNb);
1025 genericContext.currentElementIdx = nextElementIdx;
1033static bool genericContextPreparePageContent(
const nbgl_content_t *p_content,
1034 uint8_t nbElementsInPage,
1038 uint8_t nextElementIdx = genericContext.currentElementIdx;
1040 pageContent->
title = pageTitle;
1043 pageContent->
tuneId = TUNE_TAP_CASUAL;
1045 pageContent->
type = p_content->
type;
1046 switch (pageContent->
type) {
1098 p_tagValueList = NULL;
1110 genericContext.detailsItem = pair->
item;
1111 genericContext.detailsvalue = pair->
value;
1116 if (p_tagValueList != NULL) {
1117 p_tagValueList->
nbPairs = nbElementsInPage;
1120 p_tagValueList->
pairs
1123 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1125 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1131 p_tagValueList->
pairs = NULL;
1135 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1139 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1155 if ((nextElementIdx + nbElementsInPage)
1171 p_tagValueList->
nbPairs = nbElementsInPage;
1172 p_tagValueList->
pairs
1175 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1177 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1182 genericContext.currentPairs = p_tagValueList->
pairs;
1183 genericContext.currentCallback = p_tagValueList->
callback;
1207 < nextElementIdx + nbElementsInPage)) {
1227 bool isFirstOrLastPage
1231 = (navType == STREAMING_NAV)
1232 ? bundleNavContext.reviewStreaming.operationType
1233 : ((navType == GENERIC_NAV) ? bundleNavContext.review.operationType : 0);
1236 if (isFirstOrLastPage
1248 = (operationType &
BLIND_OPERATION) ? BLIND_WARNING_TOKEN : WARNING_BUTTON_TOKEN;
1255static void displayGenericContextPage(uint8_t pageIdx,
bool forceFullRefresh)
1259 uint8_t nbElementsInPage;
1263 if (navType == STREAMING_NAV) {
1265 if (bundleNavContext.reviewStreaming.skipCallback != NULL) {
1266 bundleNavContext.reviewStreaming.skipCallback();
1270 else if (pageIdx >= bundleNavContext.reviewStreaming.stepPageNb) {
1271 bundleNavReviewStreamingChoice(
true);
1278 pageIdx = navInfo.
nbPages - 1;
1284 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1289 for (
int i = navInfo.
activePage + 1; i <= pageIdx; i++) {
1290 p_content = genericContextComputeNextPageParams(i, &content, &nbElementsInPage, &flag);
1300 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1303 if (p_content == NULL) {
1307 if ((navType != STREAMING_NAV)
1310 if ((pageIdx > 0) && (pageIdx < (navInfo.
nbPages - 1))) {
1322 if (!genericContextPreparePageContent(p_content, nbElementsInPage, flag, &pageContent)) {
1328 if (forceFullRefresh) {
1337static const char *getDetailsPageAt(uint8_t detailsPage)
1340 const char *currentChar = detailsContext.value;
1341 while (page < detailsPage) {
1351 detailsContext.wrapping);
1353 if (currentChar[len] ==
'\n') {
1356 else if (detailsContext.wrapping ==
false) {
1359 currentChar = currentChar + len;
1367static void displayDetailsPage(uint8_t detailsPage,
bool forceFullRefresh)
1371 .nbPages = detailsContext.nbPages,
1373 .quitToken = QUIT_TOKEN,
1374 .navWithButtons.navToken = NAV_TOKEN,
1375 .navWithButtons.quitButton =
true,
1376 .navWithButtons.backButton =
true,
1377 .navWithButtons.quitText = NULL,
1378 .progressIndicator =
false,
1379 .tuneId = TUNE_TAP_CASUAL};
1381 .topRightIcon = NULL,
1382 .tagValueList.nbPairs = 1,
1383 .tagValueList.pairs = ¤tPair,
1384 .tagValueList.smallCaseForValue =
true,
1385 .tagValueList.wrapping = detailsContext.wrapping};
1387 if (modalPageContext != NULL) {
1390 currentPair.
item = detailsContext.tag;
1392 if (detailsPage <= detailsContext.currentPage) {
1394 currentPair.
value = getDetailsPageAt(detailsPage);
1395 forceFullRefresh =
true;
1399 currentPair.
value = detailsContext.nextPageStart;
1401 detailsContext.currentPage = detailsPage;
1412 detailsContext.wrapping);
1415 if (currentPair.
value[len] ==
'\n') {
1418 else if (!detailsContext.wrapping) {
1423 detailsContext.nextPageStart = currentPair.
value + len;
1429 detailsContext.nextPageStart = NULL;
1438 if (forceFullRefresh) {
1447static void displayFullValuePage(
const char *backText,
1448 const char *aliasText,
1451 const char *modalTitle
1452 = (extension->
backText != NULL) ? PIC(extension->
backText) : PIC(backText);
1454 genericContext.currentInfos = extension->
infolist;
1455 displayInfosListModal(modalTitle, extension->
infolist,
true);
1458 genericContext.currentTagValues = extension->
tagValuelist;
1463 .withLeftBorder =
true,
1464 .onActionCallback = &modalLayoutTouchCallback,
1465 .tapActionText = NULL};
1466 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT,
1467 .separationLine =
false,
1468 .backAndText.token = 0,
1469 .backAndText.tuneId = TUNE_TAP_CASUAL,
1470 .backAndText.text = modalTitle};
1473 nbgl_layoutAddHeader(genericContext.modalLayout, &headerDesc);
1477 nbgl_layoutQRCode_t qrCode
1479 .text1 = (extension->
title != NULL) ? extension->
title : extension->fullValue,
1480 .text2 = extension->explanation,
1484 nbgl_layoutAddQRCode(genericContext.modalLayout, &qrCode);
1489 content.
title = aliasText;
1491 content.
info =
"ENS names are resolved by Ledger backend.";
1510 nbgl_layoutAddTextContent(genericContext.modalLayout, &content);
1519static void displayInfosListModal(
const char *modalTitle,
1526 .quitToken = QUIT_TIPBOX_MODAL_TOKEN,
1527 .navWithButtons.navToken = NAV_TOKEN,
1528 .navWithButtons.quitButton =
false,
1529 .navWithButtons.backButton =
true,
1530 .navWithButtons.quitText = NULL,
1531 .progressIndicator =
false,
1532 .tuneId = TUNE_TAP_CASUAL};
1535 .topRightIcon = NULL,
1536 .infosList.nbInfos = infos->
nbInfos,
1538 .infosList.infoTypes = infos->
infoTypes,
1541 .infosList.token = fromReview ? INFO_ALIAS_TOKEN : INFOS_TIP_BOX_TOKEN,
1542 .
title = modalTitle,
1543 .titleToken = QUIT_TIPBOX_MODAL_TOKEN,
1544 .tuneId = TUNE_TAP_CASUAL};
1546 if (modalPageContext != NULL) {
1555static void displayTagValueListModalPage(uint8_t pageIdx,
bool forceFullRefresh)
1558 .nbPages = detailsContext.nbPages,
1560 .quitToken = QUIT_TOKEN,
1561 .navWithButtons.navToken = MODAL_NAV_TOKEN,
1562 .navWithButtons.quitButton =
true,
1563 .navWithButtons.backButton =
true,
1564 .navWithButtons.quitText = NULL,
1565 .progressIndicator =
false,
1566 .tuneId = TUNE_TAP_CASUAL};
1568 .topRightIcon = NULL,
1569 .tagValueList.smallCaseForValue =
true,
1570 .tagValueList.wrapping = detailsContext.wrapping};
1571 uint8_t nbElementsInPage;
1574 if (detailsContext.currentPage <= pageIdx) {
1575 modalContextGetPageInfo(pageIdx, &nbElementsInPage);
1579 modalContextGetPageInfo(pageIdx + 1, &nbElementsInPage);
1580 detailsContext.currentPairIdx -= nbElementsInPage;
1581 modalContextGetPageInfo(pageIdx, &nbElementsInPage);
1582 detailsContext.currentPairIdx -= nbElementsInPage;
1584 detailsContext.currentPage = pageIdx;
1587 = &genericContext.currentTagValues->pairs[detailsContext.currentPairIdx];
1589 detailsContext.currentPairIdx += nbElementsInPage;
1595 if (modalPageContext != NULL) {
1600 if (forceFullRefresh) {
1609static void displayAddressQRCode(
void)
1613 .withLeftBorder =
true,
1614 .onActionCallback = &modalLayoutTouchCallback,
1615 .tapActionText = NULL};
1616 nbgl_layoutHeader_t headerDesc = {
1617 .type = HEADER_EMPTY, .separationLine =
false, .emptySpace.height = SMALL_CENTERING_HEADER};
1618 nbgl_layoutQRCode_t qrCode = {.url = addressConfirmationContext.tagValuePairs[0].value,
1623 addressConfirmationContext.modalLayout =
nbgl_layoutGet(&layoutDescription);
1625 nbgl_layoutAddHeader(addressConfirmationContext.modalLayout, &headerDesc);
1628 addressConfirmationContext.tagValuePairs[0].value,
1632 if (nbLines <= QRCODE_NB_MAX_LINES) {
1633 qrCode.text2 = addressConfirmationContext.tagValuePairs[0].value;
1638 addressConfirmationContext.tagValuePairs[0].value,
1640 QRCODE_NB_MAX_LINES,
1642 QRCODE_REDUCED_ADDR_LEN);
1643 qrCode.text2 = reducedAddress;
1646 nbgl_layoutAddQRCode(addressConfirmationContext.modalLayout, &qrCode);
1648 nbgl_layoutAddFooter(
1649 addressConfirmationContext.modalLayout,
"Close", DISMISS_QR_TOKEN, TUNE_TAP_CASUAL);
1657static void modalLayoutTouchCallback(
int token, uint8_t index)
1660 if (token == DISMISS_QR_TOKEN) {
1663 addressConfirmationContext.modalLayout = NULL;
1666 else if (token == DISMISS_WARNING_TOKEN) {
1670 if (reviewWithWarnCtx.securityReportLevel <= 1) {
1671 reviewWithWarnCtx.modalLayout = NULL;
1676 reviewWithWarnCtx.securityReportLevel = 1;
1678 if (reviewWithWarnCtx.warning->predefinedSet) {
1679 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
1684 = (reviewWithWarnCtx.isIntro) ? reviewWithWarnCtx.warning->introDetails
1685 : reviewWithWarnCtx.warning->reviewDetails;
1686 displayCustomizedSecurityReport(details);
1691 else if (token == DISMISS_DETAILS_TOKEN) {
1695 if (choiceWithDetailsCtx.level <= 1) {
1696 choiceWithDetailsCtx.modalLayout = NULL;
1701 choiceWithDetailsCtx.level = 1;
1702 choiceWithDetailsCtx.modalLayout
1703 = displayModalDetails(choiceWithDetailsCtx.details, DISMISS_DETAILS_TOKEN);
1706 else if ((token >= FIRST_WARN_BAR_TOKEN) && (token <= LAST_WARN_BAR_TOKEN)) {
1707 if (sharedContext.usage == SHARE_CTX_REVIEW_WITH_WARNING) {
1710 reviewWithWarnCtx.securityReportLevel = 2;
1712 if (reviewWithWarnCtx.warning->predefinedSet) {
1713 displaySecurityReport(1 << (token - FIRST_WARN_BAR_TOKEN));
1718 = (reviewWithWarnCtx.isIntro) ? reviewWithWarnCtx.warning->introDetails
1719 : reviewWithWarnCtx.warning->reviewDetails;
1721 displayCustomizedSecurityReport(
1726 else if (sharedContext.usage == SHARE_CTX_CHOICE_WITH_DETAILS) {
1728 = &choiceWithDetailsCtx.details->
barList.
details[token - FIRST_WARN_BAR_TOKEN];
1732 choiceWithDetailsCtx.level = 2;
1733 choiceWithDetailsCtx.modalLayout
1734 = displayModalDetails(details, DISMISS_DETAILS_TOKEN);
1742 genericContext.modalLayout = NULL;
1749static void layoutTouchCallback(
int token, uint8_t index)
1752 if (token == WARNING_CHOICE_TOKEN) {
1754 reviewWithWarnCtx.choiceCallback(
false);
1757 reviewWithWarnCtx.isIntro =
false;
1758 if (reviewWithWarnCtx.isStreaming) {
1759 useCaseReviewStreamingStart(reviewWithWarnCtx.operationType,
1760 reviewWithWarnCtx.icon,
1761 reviewWithWarnCtx.reviewTitle,
1762 reviewWithWarnCtx.reviewSubTitle,
1763 reviewWithWarnCtx.choiceCallback,
1767 useCaseReview(reviewWithWarnCtx.operationType,
1768 reviewWithWarnCtx.tagValueList,
1769 reviewWithWarnCtx.icon,
1770 reviewWithWarnCtx.reviewTitle,
1771 reviewWithWarnCtx.reviewSubTitle,
1772 reviewWithWarnCtx.finishTitle,
1774 reviewWithWarnCtx.choiceCallback,
1781 else if (token == WARNING_BUTTON_TOKEN) {
1783 reviewWithWarnCtx.securityReportLevel = 1;
1785 if (reviewWithWarnCtx.warning->predefinedSet) {
1786 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
1791 ? reviewWithWarnCtx.warning->introDetails
1792 : reviewWithWarnCtx.warning->reviewDetails;
1793 displayCustomizedSecurityReport(details);
1797 else if (token == CHOICE_DETAILS_TOKEN) {
1798 choiceWithDetailsCtx.level = 1;
1799 choiceWithDetailsCtx.modalLayout
1800 = displayModalDetails(choiceWithDetailsCtx.details, DISMISS_DETAILS_TOKEN);
1803 else if (token == PRELUDE_CHOICE_TOKEN) {
1805 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->prelude->details);
1809 displayInitialWarning();
1812 reviewWithWarnCtx.isIntro =
false;
1813 if (reviewWithWarnCtx.isStreaming) {
1814 useCaseReviewStreamingStart(reviewWithWarnCtx.operationType,
1815 reviewWithWarnCtx.icon,
1816 reviewWithWarnCtx.reviewTitle,
1817 reviewWithWarnCtx.reviewSubTitle,
1818 reviewWithWarnCtx.choiceCallback,
1822 useCaseReview(reviewWithWarnCtx.operationType,
1823 reviewWithWarnCtx.tagValueList,
1824 reviewWithWarnCtx.icon,
1825 reviewWithWarnCtx.reviewTitle,
1826 reviewWithWarnCtx.reviewSubTitle,
1827 reviewWithWarnCtx.finishTitle,
1829 reviewWithWarnCtx.choiceCallback,
1837 else if (token == CHOICE_TOKEN) {
1838 if (onChoice != NULL) {
1839 onChoice((index == 0) ?
true : false);
1845static void displaySkipWarning(
void)
1848 .cancelText =
"Go back to review",
1849 .centeredInfo.text1 =
"Skip review?",
1851 =
"If you're sure you don't need to review all fields, you can skip straight to signing.",
1852 .centeredInfo.text3 = NULL,
1853 .centeredInfo.style = LARGE_CASE_INFO,
1855 .centeredInfo.offsetY = 0,
1856 .confirmationText =
"Yes, skip",
1857 .confirmationToken = SKIP_TOKEN,
1858 .
tuneId = TUNE_TAP_CASUAL,
1860 if (modalPageContext != NULL) {
1872static void updateKeyPad(
bool add)
1874 bool enableValidate, enableBackspace, enableDigits;
1875 bool redrawKeypad =
false;
1878 enableDigits = (keypadContext.pinLen < keypadContext.pinMaxDigits);
1879 enableValidate = (keypadContext.pinLen >= keypadContext.pinMinDigits);
1880 enableBackspace = (keypadContext.pinLen > 0);
1882 if ((keypadContext.pinLen == keypadContext.pinMinDigits)
1884 (keypadContext.pinLen == keypadContext.pinMaxDigits)
1886 (keypadContext.pinLen == 1)) {
1887 redrawKeypad =
true;
1891 if ((keypadContext.pinLen == 0) ||
1892 (keypadContext.pinLen == (keypadContext.pinMinDigits - 1))
1894 (keypadContext.pinLen
1895 == (keypadContext.pinMaxDigits - 1))) {
1896 redrawKeypad =
true;
1899 if (keypadContext.hidden ==
true) {
1904 keypadContext.layoutCtx,
false, 0, (
const char *) keypadContext.pinEntry);
1908 keypadContext.layoutCtx, 0, enableValidate, enableBackspace, enableDigits);
1911 if ((!add) && (keypadContext.pinLen == 0)) {
1919static void keypadCallback(
char touchedKey)
1921 switch (touchedKey) {
1923 if (keypadContext.pinLen > 0) {
1924 keypadContext.pinLen--;
1925 keypadContext.pinEntry[keypadContext.pinLen] = 0;
1927 updateKeyPad(
false);
1936 keypadContext.onValidatePin(keypadContext.pinEntry, keypadContext.pinLen);
1940 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1941 if (keypadContext.pinLen < keypadContext.pinMaxDigits) {
1942 keypadContext.pinEntry[keypadContext.pinLen] = touchedKey;
1943 keypadContext.pinLen++;
1951static void keypadGeneric_cb(
int token, uint8_t index)
1954 if (token != BACK_TOKEN) {
1963static void keyboardCallback(
char touchedKey)
1966 size_t textLen = strlen(keyboardContext.entryBuffer);
1972 keyboardContext.entryBuffer[--textLen] =
'\0';
1975 if (textLen >= keyboardContext.entryMaxLen) {
1980 keyboardContext.entryBuffer[textLen] = touchedKey;
1981 keyboardContext.entryBuffer[++textLen] =
'\0';
1986 keyboardContext.getSuggestionButtons(&keyboardContext.keyboardContent, &mask);
1988 else if (textLen >= keyboardContext.entryMaxLen) {
1992 nbgl_layoutUpdateKeyboardContent(keyboardContext.layoutCtx, &keyboardContext.keyboardContent);
1994 keyboardContext.keyboardIndex,
1997 keyboardContext.casing);
2001static void keyboardGeneric_cb(
int token, uint8_t index)
2008 case KEYBOARD_CROSS_TOKEN:
2010 keyboardContext.entryBuffer[0] =
'a';
2011 keyboardContext.entryBuffer[1] =
'\0';
2014 case KEYBOARD_BUTTON_TOKEN:
2021 && (token >= keyboardContext.keyboardContent.suggestionButtons.firstButtonToken)) {
2022 onControls(token, index);
2043static uint8_t getNbTagValuesInPage(uint8_t nbPairs,
2047 bool hasConfirmationButton,
2048 bool hasDetailsButton,
2049 bool *requireSpecificDisplay)
2051 uint8_t nbPairsInPage = 0;
2052 uint16_t currentHeight = PRE_TAG_VALUE_MARGIN;
2058 maxUsableHeight -= TOUCHABLE_HEADER_BAR_HEIGHT - SMALL_CENTERING_HEADER;
2061 *requireSpecificDisplay =
false;
2062 while (nbPairsInPage < nbPairs) {
2069 if (nbPairsInPage > 0) {
2070 currentHeight += INTER_TAG_VALUE_MARGIN;
2073 if (tagValueList->
pairs != NULL) {
2074 pair = PIC(&tagValueList->
pairs[startIndex + nbPairsInPage]);
2077 pair = PIC(tagValueList->
callback(startIndex + nbPairsInPage));
2086 if (nbPairsInPage > 0) {
2093 *requireSpecificDisplay =
true;
2102 currentHeight += TAG_VALUE_INTERVALE;
2105 value_font = SMALL_REGULAR_FONT;
2108 value_font = LARGE_MEDIUM_FONT;
2126 effectiveMaxLines = 0;
2128 if ((effectiveMaxLines > 0) && (nbLines > effectiveMaxLines)) {
2129 nbLines = effectiveMaxLines;
2142 if (nbPairsInPage == 0) {
2146 *requireSpecificDisplay =
true;
2157 if (hasConfirmationButton && (nbPairsInPage == nbPairs)) {
2158 maxUsableHeight -= UP_FOOTER_BUTTON_HEIGHT;
2159 if ((currentHeight > maxUsableHeight) && (nbPairsInPage > 1)) {
2164 else if (hasDetailsButton) {
2165 maxUsableHeight -= (SMALL_BUTTON_RADIUS * 2);
2166 if ((currentHeight > maxUsableHeight) && (nbPairsInPage > 1)) {
2170 return nbPairsInPage;
2182static uint8_t getNbTagValuesInDetailsPage(uint8_t nbPairs,
2186 uint8_t nbPairsInPage = 0;
2187 uint16_t currentHeight = PRE_TAG_VALUE_MARGIN;
2190 while (nbPairsInPage < nbPairs) {
2195 if (nbPairsInPage > 0) {
2196 currentHeight += INTER_TAG_VALUE_MARGIN;
2199 if (tagValueList->
pairs != NULL) {
2200 pair = PIC(&tagValueList->
pairs[startIndex + nbPairsInPage]);
2203 pair = PIC(tagValueList->
callback(startIndex + nbPairsInPage));
2217 if (currentHeight >= maxUsableHeight) {
2222 return nbPairsInPage;
2225static uint8_t getNbPagesForContent(
const nbgl_content_t *content,
2226 uint8_t pageIdxStart,
2230 uint8_t nbElements = 0;
2231 uint8_t nbPages = 0;
2232 uint8_t nbElementsInPage;
2233 uint8_t elemIdx = 0;
2236 nbElements = getContentNbElement(content);
2238 while (nbElements > 0) {
2241 bool hasNav = !isLast || (pageIdxStart > 0) || (elemIdx > 0);
2243 nbElementsInPage = getNbTagValuesInPage(nbElements,
2252 nbElementsInPage = getNbTagValuesInPage(nbElements,
2277 nbElementsInPage =
MIN(nbMaxElementsPerContentType[content->
type], nbElements);
2280 elemIdx += nbElementsInPage;
2281 genericContextSetPageInfo(pageIdxStart + nbPages, nbElementsInPage, flag);
2282 nbElements -= nbElementsInPage;
2290 uint8_t pageIdxStart,
2293 uint8_t nbPages = 0;
2297 for (
int i = 0; i < genericContents->
nbContents; i++) {
2298 p_content = getContentAtIdx(genericContents, i, &content);
2299 if (p_content == NULL) {
2302 nbPages += getNbPagesForContent(p_content,
2303 pageIdxStart + nbPages,
2311static void prepareAddressConfirmationPages(
const char *address,
2317 uint8_t nbAddressChunks;
2327 bool addressTruncated = (nbAddressChunks > ADDR_VERIF_NB_PAIRS);
2328 if (addressTruncated) {
2329 nbAddressChunks = ADDR_VERIF_NB_PAIRS;
2332 const char *chunkStart = address;
2333 for (uint8_t i = 0; i < nbAddressChunks; i++) {
2334 addressConfirmationContext.tagValuePairs[i].item =
"Address";
2335 addressConfirmationContext.tagValuePairs[i].value = chunkStart;
2336 addressConfirmationContext.tagValuePairs[i].forcePageStart = (i > 0);
2337 if (i + 1 < nbAddressChunks) {
2349 addressConfirmationContext.nbPairs = nbAddressChunks;
2359 if ((tagValueList != NULL) && (nbAddressChunks == 1)
2360 && (tagValueList->
nbPairs < ADDR_VERIF_NB_PAIRS)) {
2364 for (uint8_t i = 0; i < tagValueList->
nbPairs; i++) {
2365 memcpy(&addressConfirmationContext.tagValuePairs[1 + i],
2366 &tagValueList->
pairs[i],
2368 addressConfirmationContext.nbPairs++;
2372 tmpList.
nbPairs = addressConfirmationContext.nbPairs;
2373 tmpList.
pairs = addressConfirmationContext.tagValuePairs;
2374 addressConfirmationContext.nbPairs = getNbTagValuesInPage(
2375 addressConfirmationContext.nbPairs, &tmpList, 0,
false,
true,
true, &flag);
2377 if (tmpList.
nbPairs > addressConfirmationContext.nbPairs) {
2378 addressConfirmationContext.nbPairs = 1;
2389 tagValueConfirm->
tuneId = TUNE_TAP_CASUAL;
2401 uint8_t extrasPlaced
2402 = (tagValueList != NULL) ? (addressConfirmationContext.nbPairs - nbAddressChunks) : 0;
2403 bool extrasNeedSecondPage = (tagValueList != NULL) && (tagValueList->
nbPairs > extrasPlaced);
2405 if (extrasNeedSecondPage) {
2415 tagValueConfirm->
tuneId = TUNE_TAP_CASUAL;
2427static void bundleNavStartHome(
void)
2429 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
2431 useCaseHomeExt(context->appName,
2434 context->settingContents != NULL ?
true : false,
2435 &context->homeAction,
2436 bundleNavStartSettings,
2437 context->quitCallback);
2440static void bundleNavStartSettingsAtPage(uint8_t initSettingPage)
2442 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
2446 context->settingContents,
2448 bundleNavStartHome);
2451static void bundleNavStartSettings(
void)
2453 bundleNavStartSettingsAtPage(0);
2456static void bundleNavReviewConfirmRejection(
void)
2458 bundleNavContext.review.choiceCallback(
false);
2465 const char *confirmText;
2470 title =
"Reject transaction?";
2471 confirmText =
"Go back to transaction";
2474 title =
"Reject message?";
2475 confirmText =
"Go back to message";
2478 title =
"Reject operation?";
2479 confirmText =
"Go back to operation";
2486static void bundleNavReviewChoice(
bool confirm)
2489 bundleNavContext.review.choiceCallback(
true);
2492 bundleNavReviewAskRejectionConfirmation(bundleNavContext.review.operationType,
2493 bundleNavReviewConfirmRejection);
2497static void bundleNavReviewStreamingConfirmRejection(
void)
2499 bundleNavContext.reviewStreaming.choiceCallback(
false);
2502static void bundleNavReviewStreamingChoice(
bool confirm)
2505 bundleNavContext.reviewStreaming.choiceCallback(
true);
2508 bundleNavReviewAskRejectionConfirmation(bundleNavContext.reviewStreaming.operationType,
2509 bundleNavReviewStreamingConfirmRejection);
2519 .withLeftBorder =
true,
2520 .onActionCallback = modalLayoutTouchCallback,
2521 .tapActionText = NULL};
2522 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT,
2523 .separationLine =
true,
2524 .backAndText.icon = NULL,
2525 .backAndText.tuneId = TUNE_TAP_CASUAL,
2526 .backAndText.token = token};
2531 headerDesc.backAndText.text = details->
title;
2532 nbgl_layoutAddHeader(layout, &headerDesc);
2548 bar.
token = FIRST_WARN_BAR_TOKEN + i;
2549 bar.
tuneId = TUNE_TAP_CASUAL;
2550 nbgl_layoutAddTouchableBar(layout, &bar);
2551 nbgl_layoutAddSeparationLine(layout);
2557 nbgl_layoutAddQRCode(layout, &details->qrCode);
2559 headerDesc.backAndText.text = details->
title;
2564 headerDesc.separationLine =
false;
2574static void displaySecurityReport(uint32_t set)
2577 .withLeftBorder =
true,
2578 .onActionCallback = modalLayoutTouchCallback,
2579 .tapActionText = NULL};
2580 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT,
2581 .separationLine =
true,
2582 .backAndText.icon = NULL,
2583 .backAndText.tuneId = TUNE_TAP_CASUAL,
2584 .backAndText.token = DISMISS_WARNING_TOKEN};
2585 nbgl_layoutFooter_t footerDesc
2586 = {.type = FOOTER_EMPTY, .separationLine =
false, .emptySpace.height = 0};
2588 const char *provider;
2590 reviewWithWarnCtx.modalLayout =
nbgl_layoutGet(&layoutDescription);
2596 if ((reviewWithWarnCtx.securityReportLevel == 1) && (!reviewWithWarnCtx.isIntro)) {
2600 && (reviewWithWarnCtx.warning->predefinedSet & (1 << i))) {
2603 || (reviewWithWarnCtx.warning->providerMessage == NULL)) {
2604 bar.
subText = securityReportItems[i].subText;
2607 bar.
subText = reviewWithWarnCtx.warning->providerMessage;
2609 bar.
text = securityReportItems[i].text;
2612 bar.
token = FIRST_WARN_BAR_TOKEN + i;
2613 bar.
tuneId = TUNE_TAP_CASUAL;
2618 bar.
iconLeft = securityReportItems[i].icon;
2619 nbgl_layoutAddTouchableBar(reviewWithWarnCtx.modalLayout, &bar);
2620 nbgl_layoutAddSeparationLine(reviewWithWarnCtx.modalLayout);
2623 headerDesc.backAndText.text =
"Security report";
2624 nbgl_layoutAddHeader(reviewWithWarnCtx.modalLayout, &headerDesc);
2629 if (reviewWithWarnCtx.warning && reviewWithWarnCtx.warning->reportProvider) {
2630 provider = reviewWithWarnCtx.warning->reportProvider;
2633 provider =
"[unknown]";
2639 + W3C_DESCRIPTION_MAX_LEN / 2;
2642 nbgl_layoutQRCode_t qrCode = {.url = destStr,
2643 .text1 = reviewWithWarnCtx.warning->reportUrl,
2644 .text2 =
"Scan to view full report",
2649 W3C_DESCRIPTION_MAX_LEN / 2,
2651 reviewWithWarnCtx.warning->reportUrl);
2652 urlLen = strlen(destStr) + 1;
2653 nbgl_layoutAddQRCode(reviewWithWarnCtx.modalLayout, &qrCode);
2654 footerDesc.emptySpace.height = 24;
2657 snprintf(destStr + urlLen, W3C_DESCRIPTION_MAX_LEN / 2 - urlLen,
"%s report", provider);
2658 headerDesc.backAndText.text = destStr + urlLen;
2664 info.
title =
"This transaction cannot be Clear Signed";
2666 =
"This transaction or message cannot be decoded fully. If you choose to sign, you "
2667 "could be authorizing malicious actions that can drain your wallet.\n\nLearn more: "
2670 footerDesc.emptySpace.height = SMALL_CENTERING_HEADER;
2671 headerDesc.separationLine =
false;
2677 info.
title =
"Transaction Check unavailable";
2679 =
"If you're not using the Ledger Wallet app, Transaction Check might not work. If "
2681 "are using Ledger Wallet, reject the transaction and try again.\n\nGet help at "
2684 footerDesc.emptySpace.height = SMALL_CENTERING_HEADER;
2685 headerDesc.separationLine =
false;
2687 nbgl_layoutAddHeader(reviewWithWarnCtx.modalLayout, &headerDesc);
2688 if (footerDesc.emptySpace.height > 0) {
2689 nbgl_layoutAddExtendedFooter(reviewWithWarnCtx.modalLayout, &footerDesc);
2700 reviewWithWarnCtx.modalLayout = displayModalDetails(details, DISMISS_WARNING_TOKEN);
2704static void displayInitialWarning(
void)
2707#ifdef HAVE_PIEZO_SOUND
2708 tune_index_e tune = TUNE_RESERVED;
2712 nbgl_layoutChoiceButtons_t buttonsInfo = {.bottomText =
"Continue anyway",
2713 .token = WARNING_CHOICE_TOKEN,
2714 .topText =
"Back to safety",
2715 .style = ROUNDED_AND_FOOTER_STYLE,
2716 .tuneId = TUNE_TAP_CASUAL};
2717 nbgl_layoutHeader_t headerDesc = {.type = HEADER_EMPTY,
2718 .emptySpace.height = MEDIUM_CENTERING_HEADER};
2722 bool isBlindSigningOnly
2724 reviewWithWarnCtx.isIntro =
true;
2726 layoutDescription.withLeftBorder =
true;
2728 reviewWithWarnCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
2730 nbgl_layoutAddHeader(reviewWithWarnCtx.layoutCtx, &headerDesc);
2731 if (reviewWithWarnCtx.warning->predefinedSet != 0) {
2733 nbgl_layoutAddTopRightButton(reviewWithWarnCtx.layoutCtx,
2734 isBlindSigningOnly ? &INFO_I_ICON : &QRCODE_ICON,
2735 WARNING_BUTTON_TOKEN,
2738 else if (reviewWithWarnCtx.warning->introTopRightIcon != NULL) {
2739 nbgl_layoutAddTopRightButton(reviewWithWarnCtx.layoutCtx,
2740 reviewWithWarnCtx.warning->introTopRightIcon,
2741 WARNING_BUTTON_TOKEN,
2746 if (reviewWithWarnCtx.warning->predefinedSet != 0) {
2749 const char *provider;
2755 if (isBlindSigningOnly ==
false) {
2756 if (reviewWithWarnCtx.warning->reportProvider) {
2757 provider = reviewWithWarnCtx.warning->reportProvider;
2760 provider =
"[unknown]";
2763 snprintf(tmpString, W3C_DESCRIPTION_MAX_LEN,
"Detected by %s", provider);
2767 if (isBlindSigningOnly) {
2768 info.
title =
"Blind signing ahead";
2771 =
"If you sign this transaction, you could lose your assets. "
2772 "Explore safer alternatives: ledger.com/integrated-apps";
2773 buttonsInfo.bottomText =
"Accept risk and continue";
2777 =
"This transaction's details are not fully verifiable. If you sign, you could "
2778 "lose all your assets.";
2779 buttonsInfo.bottomText =
"Continue anyway";
2781#ifdef HAVE_PIEZO_SOUND
2782 tune = TUNE_NEUTRAL;
2786 info.
title =
"Potential risk";
2787 if (reviewWithWarnCtx.warning->providerMessage == NULL) {
2791 info.
description = reviewWithWarnCtx.warning->providerMessage;
2793 buttonsInfo.bottomText =
"Accept risk and continue";
2794#ifdef HAVE_PIEZO_SOUND
2795 tune = TUNE_NEUTRAL;
2799 info.
title =
"Critical threat";
2800 if (reviewWithWarnCtx.warning->providerMessage == NULL) {
2804 info.
description = reviewWithWarnCtx.warning->providerMessage;
2806 buttonsInfo.bottomText =
"Accept threat and continue";
2807#ifdef HAVE_PIEZO_SOUND
2813 else if (reviewWithWarnCtx.warning->info != NULL) {
2816#ifdef HAVE_PIEZO_SOUND
2817 tune = TUNE_LOOK_AT_ME;
2821 nbgl_layoutAddChoiceButtons(reviewWithWarnCtx.layoutCtx, &buttonsInfo);
2823#ifdef HAVE_PIEZO_SOUND
2824 if (tune != TUNE_RESERVED) {
2825 os_io_seph_cmd_piezo_play_tune(tune);
2833static void displayPrelude(
void)
2837 nbgl_layoutChoiceButtons_t buttonsInfo
2838 = {.bottomText = reviewWithWarnCtx.warning->prelude->footerText,
2839 .token = PRELUDE_CHOICE_TOKEN,
2840 .topText = reviewWithWarnCtx.warning->prelude->buttonText,
2841 .style = ROUNDED_AND_FOOTER_STYLE,
2842 .tuneId = TUNE_TAP_CASUAL};
2843 nbgl_layoutHeader_t headerDesc = {.type = HEADER_EMPTY,
2844 .emptySpace.height = MEDIUM_CENTERING_HEADER};
2847 reviewWithWarnCtx.isIntro =
true;
2849 layoutDescription.withLeftBorder =
true;
2851 reviewWithWarnCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
2853 nbgl_layoutAddHeader(reviewWithWarnCtx.layoutCtx, &headerDesc);
2858 info.
icon = reviewWithWarnCtx.warning->prelude->icon;
2860 info.
title = reviewWithWarnCtx.warning->prelude->title;
2861 info.
description = reviewWithWarnCtx.warning->prelude->description;
2865 nbgl_layoutAddChoiceButtons(reviewWithWarnCtx.layoutCtx, &buttonsInfo);
2867#ifdef HAVE_PIEZO_SOUND
2868 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
2877 const char *predefinedTipBoxText = NULL;
2880 if (reviewWithWarnCtx.warning) {
2881 if (reviewWithWarnCtx.warning->predefinedSet & (1 <<
W3C_ISSUE_WARN)) {
2883 predefinedTipBoxText =
"Transaction Check unavailable.\nBlind signing required.";
2886 predefinedTipBoxText =
"Transaction Check unavailable";
2891 predefinedTipBoxText =
"Critical threat detected.\nBlind signing required.";
2894 predefinedTipBoxText =
"Critical threat detected.";
2899 predefinedTipBoxText =
"Potential risk detected.\nBlind signing required.";
2902 predefinedTipBoxText =
"Potential risk detected.";
2907 predefinedTipBoxText
2908 =
"No threat detected by Transaction Check but blind signing required.";
2911 predefinedTipBoxText =
"No threat detected by Transaction Check.";
2915 predefinedTipBoxText =
"Blind signing required.";
2919 if ((tipBox != NULL) || (predefinedTipBoxText != NULL)) {
2921 STARTING_CONTENT.content.extendedCenter.contentCenter.subText = NULL;
2922 if (predefinedTipBoxText != NULL) {
2923 genericContext.validWarningCtx =
true;
2924 STARTING_CONTENT.content.extendedCenter.tipBox.icon = NULL;
2925 STARTING_CONTENT.content.extendedCenter.tipBox.text = predefinedTipBoxText;
2928 STARTING_CONTENT.content.extendedCenter.tipBox.icon = tipBox->
icon;
2929 STARTING_CONTENT.content.extendedCenter.tipBox.text = tipBox->
text;
2931 STARTING_CONTENT.content.extendedCenter.tipBox.token = TIP_BOX_TOKEN;
2932 STARTING_CONTENT.content.extendedCenter.tipBox.tuneId = TUNE_TAP_CASUAL;
2940 const char *reviewTitle,
2941 const char *reviewSubTitle,
2942 const char *finishTitle,
2946 bool playNotifSound)
2948 bundleNavContext.review.operationType = operationType;
2949 bundleNavContext.review.choiceCallback = choiceCallback;
2952 onChoice = bundleNavReviewChoice;
2953 navType = GENERIC_NAV;
2956 genericContext.genericContents.contentsList = localContentsList;
2957 genericContext.genericContents.nbContents = 3;
2962 prepareReviewFirstPage(
2963 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
2966 initWarningTipBox(tipBox);
2970 memcpy(&localContentsList[1].content.tagValueList,
2978 prepareReviewLightLastPage(
2979 operationType, &localContentsList[2].content.infoButton, icon, finishTitle);
2983 prepareReviewLastPage(
2984 operationType, &localContentsList[2].content.infoLongPress, icon, finishTitle);
2988 uint8_t nbPages = getNbPagesForGenericContents(
2990 prepareNavInfo(
true, nbPages, getRejectReviewText(operationType));
2993 if (playNotifSound) {
2994#ifdef HAVE_PIEZO_SOUND
2995 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
2999 displayGenericContextPage(0,
true);
3005 const char *reviewTitle,
3006 const char *reviewSubTitle,
3008 bool playNotifSound)
3010 bundleNavContext.reviewStreaming.operationType = operationType;
3011 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
3012 bundleNavContext.reviewStreaming.icon = icon;
3015 onChoice = bundleNavReviewStreamingChoice;
3016 navType = STREAMING_NAV;
3019 genericContext.genericContents.contentsList = localContentsList;
3020 genericContext.genericContents.nbContents = 1;
3025 prepareReviewFirstPage(
3026 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
3029 initWarningTipBox(NULL);
3032 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
3039 if (playNotifSound) {
3040#ifdef HAVE_PIEZO_SOUND
3041 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
3045 displayGenericContextPage(0,
true);
3064static void useCaseHomeExt(
const char *appName,
3066 const char *tagline,
3073 .centeredInfo.text1 = appName,
3074 .centeredInfo.text3 = NULL,
3075 .centeredInfo.style = LARGE_CASE_INFO,
3076 .centeredInfo.offsetY = 0,
3079 .tapActionText = NULL,
3081 .topRightToken = CONTINUE_TOKEN,
3082 .tuneId = TUNE_TAP_CASUAL};
3083 reset_callbacks_and_context();
3085 if ((homeAction->
text != NULL) || (homeAction->
icon != NULL)) {
3100 if (tagline == NULL) {
3104 "This app enables signing\ntransactions on its network.");
3131 onContinue = topRightCallback;
3132 onQuit = quitCallback;
3146static void displayDetails(
const char *tag,
const char *value,
bool wrapping)
3148 memset(&detailsContext, 0,
sizeof(detailsContext));
3154 detailsContext.tag = tag;
3155 detailsContext.value = value;
3157 detailsContext.currentPage = 0;
3158 detailsContext.wrapping = wrapping;
3160 if (detailsContext.nbPages > 1) {
3161 uint16_t nbLostChars = (detailsContext.nbPages - 1) * 3;
3164 uint8_t nbLinesInLastPage
3170 detailsContext.nbPages++;
3174 displayDetailsPage(0,
true);
3180 uint8_t nbElements = 0;
3181 uint8_t nbElementsInPage;
3182 uint8_t elemIdx = 0;
3185 memset(&detailsContext, 0,
sizeof(detailsContext));
3186 nbElements = tagValues->
nbPairs;
3188 while (nbElements > 0) {
3189 if (detailsContext.nbPages >= MAX_MODAL_PAGE_NB) {
3191 "displayTagValueListModal(): too many pages, truncating at %d\n",
3195 nbElementsInPage = getNbTagValuesInDetailsPage(nbElements, tagValues, elemIdx);
3197 elemIdx += nbElementsInPage;
3198 modalContextSetPageInfo(detailsContext.nbPages, nbElementsInPage);
3199 nbElements -= nbElementsInPage;
3200 detailsContext.nbPages++;
3203 displayTagValueListModalPage(0,
true);
3225 bool *requireSpecificDisplay)
3227 return getNbTagValuesInPage(
3228 nbPairs, tagValueList, startIndex,
false,
false,
false, requireSpecificDisplay);
3248 bool *requireSpecificDisplay)
3250 return getNbTagValuesInPage(
3251 nbPairs, tagValueList, startIndex, isSkippable,
false,
false, requireSpecificDisplay);
3268 uint8_t nbInfosInPage = 0;
3269 uint16_t currentHeight = 0;
3270 uint16_t previousHeight = 0;
3271 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3272 const char *
const *infoContents = PIC(infosList->
infoContents);
3274 while (nbInfosInPage < nbInfos) {
3277 += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING + LIST_ITEM_HEADING_SUB_TEXT;
3281 PIC(infoContents[startIndex + nbInfosInPage]),
3288 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3293 previousHeight = currentHeight;
3296 return nbInfosInPage;
3313 uint8_t nbSwitchesInPage = 0;
3314 uint16_t currentHeight = 0;
3315 uint16_t previousHeight = 0;
3316 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3319 while (nbSwitchesInPage < nbSwitches) {
3323 uint16_t textHeight =
MAX(
3324 LIST_ITEM_MIN_TEXT_HEIGHT,
3326 currentHeight += textHeight + 2 * LIST_ITEM_PRE_HEADING;
3329 currentHeight += LIST_ITEM_HEADING_SUB_TEXT;
3339 previousHeight = currentHeight;
3344 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3347 return nbSwitchesInPage;
3364 uint8_t nbBarsInPage = 0;
3365 uint16_t currentHeight = 0;
3366 uint16_t previousHeight = 0;
3367 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3372 while (nbBarsInPage < nbBars) {
3373 currentHeight += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING;
3378 previousHeight = currentHeight;
3383 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3386 return nbBarsInPage;
3403 uint8_t nbChoicesInPage = 0;
3404 uint16_t currentHeight = 0;
3405 uint16_t previousHeight = 0;
3406 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3408 UNUSED(choicesList);
3411 while (nbChoicesInPage < nbChoices) {
3412 currentHeight += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING;
3417 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3422 previousHeight = currentHeight;
3425 return nbChoicesInPage;
3436 uint8_t nbPages = 0;
3437 uint8_t nbPairs = tagValueList->
nbPairs;
3438 uint8_t nbPairsInPage;
3442 while (i < tagValueList->nbPairs) {
3446 nbPairs -= nbPairsInPage;
3456void nbgl_useCaseHome(
const char *appName,
3458 const char *tagline,
3465 appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
3472void nbgl_useCaseHomeExt(
const char *appName,
3474 const char *tagline,
3476 const char *actionButtonText,
3484 .text = actionButtonText};
3487 appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
3510 reset_callbacks_and_context();
3513 onQuit = quitCallback;
3514 onNav = navCallback;
3515 onControls = controlsCallback;
3517 navType = SETTINGS_NAV;
3520 prepareNavInfo(
false, nbPages, NULL);
3522 displaySettingsPage(initPage,
true);
3530void nbgl_useCaseSettings(
const char *title,
3540 title, initPage, nbPages, quitCallback, navCallback, controlsCallback);
3561 reset_callbacks_and_context();
3564 onQuit = quitCallback;
3565 pageTitle = appName;
3566 navType = GENERIC_NAV;
3568 if (settingContents != NULL) {
3571 if (infosList != NULL) {
3572 genericContext.hasFinishingContent =
true;
3575 memcpy(&FINISHING_CONTENT.content, infosList,
sizeof(
nbgl_content_u));
3579 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
3580 if (infosList != NULL) {
3581 nbPages += getNbPagesForContent(&FINISHING_CONTENT, nbPages,
true,
false);
3584 prepareNavInfo(
false, nbPages, NULL);
3586 displayGenericContextPage(initPage,
true);
3625 const char *appName,
3627 const char *tagline,
3635 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
3637 reset_callbacks_and_context();
3639 context->appName = appName;
3640 context->appIcon = appIcon;
3641 context->tagline = tagline;
3642 context->settingContents = settingContents;
3643 context->infosList = infosList;
3644 if (action != NULL) {
3650 context->quitCallback = quitCallback;
3653 bundleNavStartSettingsAtPage(initSettingPage);
3656 bundleNavStartHome();
3670 .tickerIntervale = 0,
3674 reset_callbacks_and_context();
3676 onQuit = quitCallback;
3678#ifdef HAVE_PIEZO_SOUND
3679 os_io_seph_cmd_piezo_play_tune(TUNE_LEDGER_MOMENT);
3687 info.
tuneId = TUNE_TAP_CASUAL;
3703 switch (reviewStatusType) {
3705 msg =
"Operation signed";
3709 msg =
"Operation rejected";
3713 msg =
"Transaction signed";
3717 msg =
"Transaction rejected";
3721 msg =
"Message signed";
3725 msg =
"Message rejected";
3729 msg =
"Address verified";
3733 msg =
"Address verification\ncancelled";
3755 const char *message,
3756 const char *subMessage,
3757 const char *confirmText,
3758 const char *cancelText,
3763 if ((confirmText == NULL) || (cancelText == NULL)) {
3767 reset_callbacks_and_context();
3776 info.
tuneId = TUNE_TAP_CASUAL;
3778 onChoice = callback;
3798 const char *message,
3799 const char *subMessage,
3800 const char *confirmText,
3801 const char *cancelText,
3806 (details != NULL) ? &SEARCH_ICON : NULL,
3841 const char *message,
3842 const char *subMessage,
3843 const char *confirmText,
3844 const char *cancelText,
3850 nbgl_layoutChoiceButtons_t buttonsInfo = {.bottomText = cancelText,
3851 .token = CHOICE_TOKEN,
3852 .topText = confirmText,
3853 .style = ROUNDED_AND_FOOTER_STYLE,
3854 .tuneId = TUNE_TAP_CASUAL};
3856 nbgl_layoutHeader_t headerDesc = {.type = HEADER_EMPTY,
3857 .emptySpace.height = MEDIUM_CENTERING_HEADER};
3860 if ((confirmText == NULL) || (cancelText == NULL)) {
3862 "nbgl_useCaseAdvancedChoiceWithDetails(): confirmText or cancelText is NULL\n");
3866 reset_callbacks_and_context();
3868#ifdef HAVE_PIEZO_SOUND
3869 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
3872 onChoice = callback;
3873 layoutDescription.withLeftBorder =
true;
3875 sharedContext.usage = SHARE_CTX_CHOICE_WITH_DETAILS;
3876 choiceWithDetailsCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
3877 choiceWithDetailsCtx.details = details;
3879 nbgl_layoutAddHeader(choiceWithDetailsCtx.layoutCtx, &headerDesc);
3880 nbgl_layoutAddChoiceButtons(choiceWithDetailsCtx.layoutCtx, &buttonsInfo);
3881 centeredInfo.
icon = centerIcon;
3882 centeredInfo.
title = title;
3884 centeredInfo.
subText = subMessage;
3887 if ((details != NULL) && (headerIcon != NULL)) {
3888 nbgl_layoutAddTopRightButton(
3889 choiceWithDetailsCtx.layoutCtx, headerIcon, CHOICE_DETAILS_TOKEN, TUNE_TAP_CASUAL);
3910 const char *subMessage,
3911 const char *confirmText,
3912 const char *cancelText,
3918 .centeredInfo.text1 = message,
3919 .centeredInfo.text2 = subMessage,
3920 .centeredInfo.text3 = NULL,
3921 .centeredInfo.style = LARGE_CASE_INFO,
3923 .centeredInfo.offsetY = 0,
3924 .confirmationText = confirmText,
3925 .confirmationToken = CHOICE_TOKEN,
3926 .tuneId = TUNE_TAP_CASUAL,
3928 onModalConfirm = callback;
3929 if (modalPageContext != NULL) {
3947 const char *message,
3948 const char *actionText,
3953 reset_callbacks_and_context();
3955 onAction = callback;
3957 content.
tuneId = TUNE_TAP_CASUAL;
3980 const char *reviewTitle,
3981 const char *reviewSubTitle,
3982 const char *rejectText,
3987 .footerToken = QUIT_TOKEN,
3988 .tapActionText = NULL,
3989 .isSwipeable =
true,
3990 .tapActionToken = CONTINUE_TOKEN,
3992 .actionButtonText = NULL,
3993 .
tuneId = TUNE_TAP_CASUAL};
3995 reset_callbacks_and_context();
4003 onQuit = rejectCallback;
4004 onContinue = continueCallback;
4006#ifdef HAVE_PIEZO_SOUND
4008 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4019void nbgl_useCaseRegularReview(uint8_t initPage,
4021 const char *rejectText,
4026 reset_callbacks_and_context();
4029 onChoice = choiceCallback;
4030 onNav = navCallback;
4032 forwardNavOnly =
false;
4033 navType = REVIEW_NAV;
4037 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
4039 displayReviewPage(initPage,
true);
4056 const char *rejectText,
4061 reset_callbacks_and_context();
4064 onChoice = callback;
4065 navType = GENERIC_NAV;
4069 genericContext.genericContents.contentsList = localContentsList;
4072 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
4074 memcpy(&localContentsList[offset].content.tagValueList,
4081 memcpy(&localContentsList[offset].content.infoLongPress,
4087 genericContext.genericContents.nbContents = offset;
4090 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4092 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
4094 displayGenericContextPage(0,
true);
4112 const char *rejectText,
4117 reset_callbacks_and_context();
4120 onChoice = callback;
4121 navType = GENERIC_NAV;
4124 genericContext.genericContents.contentsList = localContentsList;
4127 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
4129 memcpy(&localContentsList[offset].content.tagValueList,
4143 genericContext.genericContents.nbContents = offset;
4146 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4148 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
4150 displayGenericContextPage(0,
true);
4172 const char *reviewTitle,
4173 const char *reviewSubTitle,
4174 const char *finishTitle,
4177 reset_callbacks_and_context();
4179 useCaseReview(operationType,
4213 const char *reviewTitle,
4214 const char *reviewSubTitle,
4215 const char *finishTitle,
4226 &blindSigningWarning,
4255 const char *reviewTitle,
4256 const char *reviewSubTitle,
4257 const char *finishTitle,
4262 reset_callbacks_and_context();
4265 if (tipBox != NULL) {
4266 memcpy(&activeTipBox, tipBox,
sizeof(activeTipBox));
4269 if ((warning == NULL)
4272 useCaseReview(operationType,
4290 sharedContext.usage = SHARE_CTX_REVIEW_WITH_WARNING;
4291 reviewWithWarnCtx.isStreaming =
false;
4292 reviewWithWarnCtx.operationType = operationType;
4293 reviewWithWarnCtx.tagValueList = tagValueList;
4294 reviewWithWarnCtx.icon = icon;
4295 reviewWithWarnCtx.reviewTitle = reviewTitle;
4296 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
4297 reviewWithWarnCtx.finishTitle = finishTitle;
4298 reviewWithWarnCtx.warning = warning;
4299 reviewWithWarnCtx.choiceCallback = choiceCallback;
4302 if (reviewWithWarnCtx.warning->prelude) {
4307 displayInitialWarning();
4310 useCaseReview(operationType,
4342 const char *reviewTitle,
4343 const char *reviewSubTitle,
4344 const char *finishTitle,
4347 reset_callbacks_and_context();
4349 useCaseReview(operationType,
4370 const char *rejectText,
4373 reset_callbacks_and_context();
4376 onQuit = rejectCallback;
4377 navType = GENERIC_NAV;
4384 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4385 prepareNavInfo(
true, nbPages, rejectText);
4388#ifdef HAVE_PIEZO_SOUND
4390 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4393 displayGenericContextPage(0,
true);
4410 const char *reviewTitle,
4411 const char *reviewSubTitle,
4414 reset_callbacks_and_context();
4416 useCaseReviewStreamingStart(
4417 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4435 const char *reviewTitle,
4436 const char *reviewSubTitle,
4440 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
4460 const char *reviewTitle,
4461 const char *reviewSubTitle,
4465 reset_callbacks_and_context();
4468 if ((warning == NULL)
4471 useCaseReviewStreamingStart(
4472 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4482 sharedContext.usage = SHARE_CTX_REVIEW_WITH_WARNING;
4483 reviewWithWarnCtx.isStreaming =
true;
4484 reviewWithWarnCtx.operationType = operationType;
4485 reviewWithWarnCtx.icon = icon;
4486 reviewWithWarnCtx.reviewTitle = reviewTitle;
4487 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
4488 reviewWithWarnCtx.choiceCallback = choiceCallback;
4489 reviewWithWarnCtx.warning = warning;
4492 if (reviewWithWarnCtx.warning->prelude) {
4497 displayInitialWarning();
4500 useCaseReviewStreamingStart(
4501 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4523 memset(&genericContext, 0,
sizeof(genericContext));
4525 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
4526 bundleNavContext.reviewStreaming.skipCallback = skipCallback;
4529 onChoice = bundleNavReviewStreamingChoice;
4530 navType = STREAMING_NAV;
4533 genericContext.genericContents.contentsList = localContentsList;
4534 genericContext.genericContents.nbContents = 1;
4543 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
4544 &genericContext.genericContents,
4547 prepareNavInfo(
true,
4549 getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
4557 displayGenericContextPage(0,
true);
4588 memset(&genericContext, 0,
sizeof(genericContext));
4590 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
4593 onChoice = bundleNavReviewStreamingChoice;
4594 navType = STREAMING_NAV;
4597 genericContext.genericContents.contentsList = localContentsList;
4598 genericContext.genericContents.nbContents = 1;
4603 prepareReviewLastPage(bundleNavContext.reviewStreaming.operationType,
4604 &STARTING_CONTENT.content.infoLongPress,
4605 bundleNavContext.reviewStreaming.icon,
4609 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
4610 &genericContext.genericContents,
4613 prepareNavInfo(
true, 1, getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
4615 displayGenericContextPage(0,
true);
4622void nbgl_useCaseAddressConfirmationExt(
const char *address,
4626 reset_callbacks_and_context();
4627 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
4630 onChoice = callback;
4631 navType = GENERIC_NAV;
4634 genericContext.genericContents.contentsList = localContentsList;
4635 genericContext.genericContents.nbContents = (tagValueList == NULL) ? 1 : 2;
4637 prepareAddressConfirmationPages(
4638 address, tagValueList, &STARTING_CONTENT, &localContentsList[1]);
4641 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4643 prepareNavInfo(
true, nbPages,
"Cancel");
4645#ifdef HAVE_PIEZO_SOUND
4647 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4650 displayGenericContextPage(0,
true);
4672 const char *reviewTitle,
4673 const char *reviewSubTitle,
4676 reset_callbacks_and_context();
4679 if (addressConfirmationContext.modalLayout) {
4682 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
4685 onChoice = choiceCallback;
4686 navType = GENERIC_NAV;
4690 genericContext.genericContents.contentsList = localContentsList;
4695 prepareReviewFirstPage(
4696 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
4697 STARTING_CONTENT.content.extendedCenter.contentCenter.subText =
"Swipe to continue";
4700 prepareAddressConfirmationPages(
4701 address, additionalTagValueList, &localContentsList[1], &localContentsList[2]);
4704 genericContext.genericContents.nbContents
4706 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4708 prepareNavInfo(
true, nbPages,
"Cancel");
4710#ifdef HAVE_PIEZO_SOUND
4712 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4715 displayGenericContextPage(0,
true);
4729 if (genericContext.type != USE_CASE_SPINNER) {
4730 memset(&genericContext, 0,
sizeof(genericContext));
4731 genericContext.type = USE_CASE_SPINNER;
4734 layoutDescription.withLeftBorder =
true;
4736 genericContext.backgroundLayout =
nbgl_layoutGet(&layoutDescription);
4738 nbgl_layoutAddSpinner(
4739 genericContext.backgroundLayout, text, NULL, genericContext.spinnerPosition);
4746 genericContext.spinnerPosition++;
4748 if (genericContext.spinnerPosition == NB_SPINNER_POSITIONS) {
4749 genericContext.spinnerPosition = 0;
4751 int ret = nbgl_layoutUpdateSpinner(
4752 genericContext.backgroundLayout, text, NULL, genericContext.spinnerPosition);
4756 else if (ret == 2) {
4790 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT,
4791 .separationLine =
true,
4792 .backAndText.token = BACK_TOKEN,
4793 .backAndText.tuneId = TUNE_TAP_CASUAL};
4798 "nbgl_useCaseKeypad(): digits out of range (%d/%d > %d)\n",
4805 reset_callbacks_and_context();
4807 memset(&keypadContext, 0,
sizeof(KeypadContext_t));
4810 onQuit = backCallback;
4815 keypadContext.hidden = hidden;
4818 nbgl_layoutAddHeader(keypadContext.layoutCtx, &headerDesc);
4824 USE_CASE_LOGGER,
"nbgl_useCaseKeypad(): layout setup failed (status=%d)\n", status);
4829 keypadContext.layoutCtx, title, keypadContext.hidden, maxDigits,
"");
4832 USE_CASE_LOGGER,
"nbgl_useCaseKeypad(): layout setup failed (status=%d)\n", status);
4837 keypadContext.onValidatePin = validatePinCallback;
4839 keypadContext.pinMinDigits = minDigits;
4840 keypadContext.pinMaxDigits = maxDigits;
4879 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_TEXT,
4880 .backAndText.token = BACK_TOKEN,
4881 .backAndText.tuneId = TUNE_TAP_CASUAL};
4884 .mode = params->
mode,
4885 .casing = params->casing};
4889 reset_callbacks_and_context();
4891 memset(&keyboardContext, 0,
sizeof(KeyboardContext_t));
4894 onQuit = backCallback;
4900 nbgl_layoutAddHeader(keyboardContext.layoutCtx, &headerDesc);
4906 USE_CASE_LOGGER,
"nbgl_useCaseKeyboard(): layout setup failed (status=%d)\n", status);
4909 keyboardContext.keyboardIndex = status;
4910 keyboardContext.casing = params->casing;
4912 keyboardContext.entryMaxLen = params->
entryMaxLen;
4913 keyboardContext.entryBuffer[0] =
'\0';
4916 .type = params->
type,
4917 .title = PIC(params->
title),
4918 .numbered = params->numbered,
4919 .number = params->number,
4920 .obfuscated = params->obfuscated,
4922 .textToken = KEYBOARD_CROSS_TOKEN,
4923 .tuneId = TUNE_TAP_CASUAL,
4925 switch (params->
type) {
4930 .token = KEYBOARD_BUTTON_TOKEN,
4936 keyboardContext.getSuggestionButtons
4946 status = nbgl_layoutAddKeyboardContent(keyboardContext.layoutCtx,
4947 &keyboardContext.keyboardContent);
4950 USE_CASE_LOGGER,
"nbgl_useCaseKeyboard(): layout setup failed (status=%d)\n", status);
nbgl_contentTagValue_t *(* nbgl_contentTagValueCallback_t)(uint8_t pairIndex)
prototype of tag/value pair retrieval callback
@ ICON_ILLUSTRATION
simple icon
@ INFO_LONG_PRESS
a centered info and a long press button
@ EXTENDED_CENTER
a centered content and a possible tip-box
@ CHOICES_LIST
list of choices through radio buttons
@ CENTERED_INFO
a centered info
@ SWITCHES_LIST
list of switches with descriptions
@ TAG_VALUE_DETAILS
a tag/value pair and a small button to get details.
@ INFOS_LIST
list of infos with titles
@ TAG_VALUE_CONFIRM
tag/value pairs and a black button/footer to confirm/cancel.
@ TAG_VALUE_LIST
list of tag/value pairs
@ BARS_LIST
list of touchable bars (with > on the right to go to sub-pages)
@ INFO_BUTTON
a centered info and a simple black button
@ INFO_LIST_ALIAS
alias is list of infos
@ ENS_ALIAS
alias comes from ENS
@ ADDRESS_BOOK_ALIAS
alias comes from Address Book
@ QR_CODE_ALIAS
alias is an address to be displayed as a QR Code
void(* nbgl_contentActionCallback_t)(int token, uint8_t index, int page)
prototype of function to be called when an action on a content object occurs
#define LOG_WARN(__logger,...)
#define LOG_DEBUG(__logger,...)
static void actionCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
uint8_t nbgl_getTextNbPagesInWidth(nbgl_font_id_e fontId, const char *text, uint8_t nbLinesPerPage, uint16_t maxWidth)
bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t maxNbLines, uint16_t *len, bool wrapping)
void nbgl_textReduceOnNbLines(nbgl_font_id_e fontId, const char *origText, uint16_t maxWidth, uint8_t nbLines, char *reducedText, uint16_t reducedTextLen)
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
#define LARGE_WARNING_ICON
#define IMPORTANT_CIRCLE_ICON
#define CHECK_CIRCLE_ICON
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
int nbgl_layoutAddContentCenter(nbgl_layout_t *layout, const nbgl_contentCenter_t *info)
int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInfo)
Creates a keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutUpdateKeyboard(nbgl_layout_t *layout, uint8_t index, uint32_t keyMask)
Updates an existing keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutUpdateKeypad(nbgl_layout_t *layout, uint8_t index, bool enableValidate, bool enableBackspace)
Updates an existing keypad on bottom of the screen, with the given configuration.
int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, bool hidden, uint8_t nbDigits, const char *text)
Adds an area with a title and a placeholder for hidden digits on top of a keypad, to represent the en...
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
void * nbgl_layout_t
type shared externally
#define NBGL_INVALID_TOKEN
int nbgl_layoutUpdateKeypadContent(nbgl_layout_t *layout, bool hidden, uint8_t nbActiveDigits, const char *text)
Updates an existing set of hidden digits, with the given configuration.
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
#define NBGL_NO_PROGRESS_INDICATOR
To be used when a control token shall not be used.
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, const char *text, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
int nbgl_layoutRelease(nbgl_layout_t *layout)
Release the layout obtained with nbgl_layoutGet()
static void buttonCallback(nbgl_screen_t *screen, nbgl_buttonEvent_t buttonEvent)
keyboardCase_t
Letters casing in which to open/set the keyboard.
#define KEYPAD_MAX_DIGITS
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
nbgl_page_t * nbgl_pageDrawGenericContent(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageNavigationInfo_t *nav, nbgl_pageContent_t *content)
nbgl_page_t * nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_screenTickerConfiguration_t *ticker, const nbgl_pageInfoDescription_t *info)
void * nbgl_page_t
type shared externally
@ NAV_WITH_BUTTONS
move forward and backward with buttons in bottom nav bar
nbgl_page_t * nbgl_pageDrawConfirmation(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageConfirmationDescription_t *info)
int nbgl_pageRelease(nbgl_page_t *)
nbgl_page_t * nbgl_pageDrawGenericContentExt(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageNavigationInfo_t *nav, nbgl_pageContent_t *content, bool modal)
@ QUIT_APP_TEXT
A full width button with "Quit app" text (only for bottom button)
@ INFO_ICON
info (i) icon in the button.
@ NO_BUTTON_STYLE
no button.
@ SETTINGS_ICON
settings (wheel) icon in the button.
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screenRedraw(void)
@ POST_REFRESH_FORCE_POWER_ON
Force screen power on after refresh.
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
nbgl_refresh_mode_t
different modes of refresh for nbgl_refreshSpecial()
@ BLACK_AND_WHITE_REFRESH
to be used for pure B&W area, when contrast is important
@ FULL_COLOR_CLEAN_REFRESH
to be used for lock screen display (cleaner but longer refresh)
@ BLACK_AND_WHITE_FAST_REFRESH
to be used for pure B&W area, when contrast is not priority
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
@ FULL_COLOR_REFRESH
to be used for normal refresh
API of the Advanced BOLOS Graphical Library, for typical application use-cases.
#define NB_MAX_LINES_IN_REVIEW
maximum number of lines for value field in review pages
@ NO_TYPE_WARNING
Invalid type (to use for bars leading to nothing)
@ CENTERED_INFO_WARNING
Centered info.
@ BAR_LIST_WARNING
list of touchable bars, to display sub-pages
uint8_t nbgl_useCaseGetNbTagValuesInPageExt(uint8_t nbPairs, const nbgl_contentTagValueList_t *tagValueList, uint8_t startIndex, bool isSkippable, bool *requireSpecificDisplay)
void(* nbgl_callback_t)(void)
prototype of generic callback function
#define SKIPPABLE_OPERATION
This is to use in nbgl_operationType_t when the operation is skippable. This is used to add a Skip bu...
void nbgl_useCaseGenericSettings(const char *appName, uint8_t initPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, nbgl_callback_t quitCallback)
uint32_t nbgl_operationType_t
This mask is used to describe the type of operation to review with additional options It is a mask of...
void nbgl_useCaseReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseAction(const nbgl_icon_details_t *icon, const char *message, const char *actionText, nbgl_callback_t callback)
uint8_t nbgl_useCaseGetNbTagValuesInPage(uint8_t nbPairs, const nbgl_contentTagValueList_t *tagValueList, uint8_t startIndex, bool *requireSpecificDisplay)
uint8_t nbgl_useCaseGetNbPagesForTagValueList(const nbgl_contentTagValueList_t *tagValueList)
void(* nbgl_pinValidCallback_t)(const uint8_t *pin, uint8_t pinLen)
prototype of pin validation callback function
void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseHomeAndSettings(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, const uint8_t initSettingPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, const nbgl_homeAction_t *action, nbgl_callback_t quitCallback)
#define RISKY_OPERATION
This is to use in nbgl_operationType_t when the operation is concerned by an internal warning....
uint8_t nbgl_useCaseGetNbInfosInPage(uint8_t nbInfos, const nbgl_contentInfoList_t *infosList, uint8_t startIndex, bool withNav)
void(* nbgl_choiceCallback_t)(bool confirm)
prototype of choice callback function
uint8_t nbgl_useCaseGetNbBarsInPage(uint8_t nbBars, const nbgl_contentBarsList_t *barsList, uint8_t startIndex, bool withNav)
void nbgl_useCaseNavigableContent(const char *title, uint8_t initPage, uint8_t nbPages, nbgl_callback_t quitCallback, nbgl_navCallback_t navCallback, nbgl_layoutTouchCallback_t controlsCallback)
#define INFOS_AREA_HEIGHT
height available for infos pairs display
@ STRONG_HOME_ACTION
Black button, implicating the main action of the App.
void nbgl_useCaseReviewStreamingFinish(const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
#define NO_THREAT_OPERATION
This is to use in nbgl_operationType_t when the operation is concerned by an internal information....
void nbgl_useCaseChoiceWithDetails(const nbgl_icon_details_t *icon, const char *message, const char *subMessage, const char *confirmText, const char *cancelText, nbgl_warningDetails_t *details, nbgl_choiceCallback_t callback)
void nbgl_useCaseAdvancedChoiceWithDetails(const nbgl_icon_details_t *centerIcon, const nbgl_icon_details_t *headerIcon, const char *title, const char *message, const char *subMessage, const char *confirmText, const char *cancelText, nbgl_warningDetails_t *details, nbgl_choiceCallback_t callback)
void nbgl_useCaseSpinner(const char *text)
void nbgl_useCaseConfirm(const char *message, const char *subMessage, const char *confirmText, const char *rejectText, nbgl_callback_t callback)
#define NB_MAX_LINES_IN_DETAILS
maximum number of lines for value field in details pages
#define APP_DESCRIPTION_MAX_LEN
Length of buffer used for the default Home tagline.
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
@ W3C_THREAT_DETECTED_WARN
Web3 Checks: Threat detected (see reportRisk field)
@ W3C_ISSUE_WARN
Web3 Checks issue (not available)
@ BLIND_SIGNING_WARN
Blind signing.
@ GATED_SIGNING_WARN
Gated signing.
@ W3C_NO_THREAT_WARN
Web3 Checks: No Threat detected.
@ W3C_RISK_DETECTED_WARN
Web3 Checks: Risk detected (see reportRisk field)
void nbgl_useCaseGenericConfiguration(const char *title, uint8_t initPage, const nbgl_genericContents_t *contents, nbgl_callback_t quitCallback)
#define INIT_HOME_PAGE
Value to pass to nbgl_useCaseHomeAndSettings() initSettingPage parameter to initialize the use case o...
void nbgl_useCaseKeypad(const char *title, uint8_t minDigits, uint8_t maxDigits, bool shuffled, bool hidden, nbgl_pinValidCallback_t validatePinCallback, nbgl_callback_t backCallback)
void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback, nbgl_callback_t skipCallback)
void nbgl_useCaseReviewBlindSigning(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, const nbgl_tipBox_t *tipBox, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseChoice(const nbgl_icon_details_t *icon, const char *message, const char *subMessage, const char *confirmText, const char *rejectString, nbgl_choiceCallback_t callback)
#define FIRST_USER_TOKEN
when using controls in page content (nbgl_pageContent_t), this is the first token value usable for th...
#define TAG_VALUE_AREA_HEIGHT
height available for tag/value pairs display
#define BLIND_OPERATION
This is to use in nbgl_operationType_t when the operation is "blind" This is used to indicate a warni...
#define TAGLINE_PART1
Default strings used in the Home tagline.
void nbgl_useCaseGenericReview(const nbgl_genericContents_t *contents, const char *rejectText, nbgl_callback_t rejectCallback)
#define STATUS_SCREEN_DURATION
void nbgl_useCaseKeyboard(const nbgl_keyboardParams_t *params, nbgl_callback_t backCallback)
void nbgl_useCaseReviewStreamingBlindSigningStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewLight(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
uint8_t nbgl_useCaseGetNbChoicesInPage(uint8_t nbChoices, const nbgl_contentRadioChoice_t *choicesList, uint8_t startIndex, bool withNav)
void(* nbgl_keyboardButtonsCallback_t)(nbgl_layoutKeyboardContent_t *content, uint32_t *mask)
prototype of keyboard buttons callback function
#define REAL_TYPE_MASK
Mask to apply on nbgl_operationType_t to extract the base nbgl_opType_t. Bits 0-3 are reserved for th...
void nbgl_useCaseReviewStatus(nbgl_reviewStatusType_t reviewStatusType, nbgl_callback_t quitCallback)
#define LAST_PAGE_FOR_REVIEW
value of page parameter used with navigation callback when "skip" button is touched,...
#define ADDRESS_BOOK_OPERATION
This is to use in nbgl_operationType_t when the operation is related to "Address Book" to adapt wordi...
nbgl_reviewStatusType_t
The different types of review status.
@ STATUS_TYPE_TRANSACTION_REJECTED
@ STATUS_TYPE_ADDRESS_REJECTED
@ STATUS_TYPE_TRANSACTION_SIGNED
@ STATUS_TYPE_OPERATION_REJECTED
@ STATUS_TYPE_OPERATION_SIGNED
@ STATUS_TYPE_ADDRESS_VERIFIED
@ STATUS_TYPE_MESSAGE_SIGNED
@ STATUS_TYPE_MESSAGE_REJECTED
bool(* nbgl_navCallback_t)(uint8_t page, nbgl_pageContent_t *content)
prototype of navigation callback function
#define MAX_APP_NAME_FOR_SDK_TAGLINE
Max supported length of appName used for the default Home tagline.
#define HAS_INITIAL_WARNING(_warning)
void nbgl_useCaseAddressReview(const char *address, const nbgl_contentTagValueList_t *additionalTagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
@ TYPE_TRANSACTION
For operations transferring a coin or taken from an account to another.
@ TYPE_OPERATION
For other types of operation (generic type)
void nbgl_useCaseAdvancedReviewStreamingStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const nbgl_warning_t *warning, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseAdvancedReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, const nbgl_tipBox_t *tipBox, const nbgl_warning_t *warning, nbgl_choiceCallback_t choiceCallback)
uint8_t nbgl_useCaseGetNbSwitchesInPage(uint8_t nbSwitches, const nbgl_contentSwitchesList_t *switchesList, uint8_t startIndex, bool withNav)
This structure contains data to build a BARS_LIST content.
const uint8_t * tokens
array of tokens, one for each bar (nbBars items)
const char *const * barTexts
array of texts for each bar (nbBars items, in black/bold)
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when a bar is touched
uint8_t nbBars
number of elements in barTexts and tokens array
This structure contains info to build a centered (vertically and horizontally) area,...
uint16_t iconHug
vertical margin to apply on top and bottom of the icon
const nbgl_icon_details_t * icon
the icon (can be null)
const char * title
title in black large (can be null)
const char * description
description in black small regular case (can be null)
const char * subText
sub-text in dark gray regular small case
bool padding
if true, apply a padding of 40px at the bottom
const char * smallTitle
sub-title in black small bold case (can be null)
nbgl_contentIllustrationType_t illustrType
const char * text2
second text (can be null)
const char * text1
first text (can be null)
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
nbgl_contentCenter_t contentCenter
centered content (icon + text(s))
This structure contains data to build a centered info + simple black button content.
const char * buttonText
text of the long press button
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
const char * text
centered text in large case
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when button is touched
This structure contains data to build a INFOS_LIST content.
const char *const * infoContents
array of contents of infos (in black)
const char *const * infoTypes
array of types of infos (in black/bold)
const nbgl_contentValueExt_t * infoExtensions
uint8_t nbInfos
number of elements in infoTypes and infoContents array
This structure contains data to build a centered info + long press button content.
const char * longPressText
text of the long press button
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
const char * text
centered text in large case
This structure contains a list of names to build a list of radio buttons (on the right part of screen...
uint8_t initChoice
index of the current choice
const char *const * names
array of strings giving the choices (nbChoices)
uint8_t nbChoices
number of choices
This structure contains info to build a switch (on the right) with a description (on the left),...
const char * text
main text for the switch
const char * subText
description under main text (NULL terminated, single line, may be null)
This structure contains [item,value] pair(s) and info about a potential "details" button,...
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when details button is touched
const char * confirmationText
text of the confirmation button, if NULL "It matches" is used
uint8_t detailsButtonToken
uint8_t confirmationToken
the token used as argument of the onActionCallback
nbgl_contentTagValueList_t tagValueList
list of tag/value pairs
const char * detailsButtonText
this text is used for "details" button (if NULL, no button)
const nbgl_icon_details_t * detailsButtonIcon
icon to use in details button
const nbgl_icon_details_t * detailsButtonIcon
icon to use in details button
uint8_t detailsButtonToken
const char * detailsButtonText
this text is used for "details" button
nbgl_contentTagValueList_t tagValueList
list of tag/value pairs
This structure contains a list of [tag,value] pairs.
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
uint8_t nbMaxLinesForValue
if > 0, set the max number of lines for value field.
bool hideEndOfLastLine
if set to true, replace 3 last chars of last line by "..."
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
uint8_t startIndex
index of the first pair to get with callback
nbgl_contentActionCallback_t actionCallback
called when a valueIcon is touched on a given pair
This structure contains a [tag,value] pair and possible extensions.
const nbgl_contentValueExt_t * extension
if not NULL, gives additional info on value field
const nbgl_icon_details_t * valueIcon
const char * value
string giving the value name
const char * item
string giving the tag name
uint8_t centeredInfo
if set to 1, the tag will be displayed as a centered info
This structure contains additions to a tag/value pair, to be able to build a screen to display these ...
const char * fullValue
full string of the value when used as an alias
nbgl_contentValueAliasType_t aliasType
type of alias
const struct nbgl_contentTagValueList_s * tagValuelist
if aliasType is TAG_VALUE_LIST_ALIAS
const char * backText
used as title of the popping page, if not NULL, otherwise "item" is used
const char * aliasSubName
string displayed under alias and in details view
const struct nbgl_contentInfoList_s * infolist
if aliasType is INFO_LIST_ALIAS
This structure contains data to build a content.
nbgl_contentActionCallback_t contentActionCallback
callback to be called when an action on an object occurs
nbgl_contentType_t type
type of page content in the content union
const struct nbgl_genericDetails_s * details
array of nbBars structures giving what to display when each bar is touched.
uint8_t nbBars
number of touchable bars
const nbgl_icon_details_t ** icons
array of icons for each bar (nbBars items)
const char *const * subTexts
array of texts for each bar (nbBars items, in black)
const char *const * texts
array of texts for each bar (nbBars items, in black/bold)
uint8_t nbContents
number of contents
const nbgl_content_t * contentsList
array of nbgl_content_t (nbContents items).
nbgl_contentCallback_t contentGetterCallback
function to call to retrieve a given content
The necessary parameters to build the page(s) displayed when the top-right button is touched in intro...
const char * title
text of the page (used to go back)
nbgl_genericBarList_t barList
touchable bars list, if type == BAR_LIST_WARNING
nbgl_genericDetailsType_t type
type of content in the page, determining what to use in the following union
nbgl_contentCenter_t centeredInfo
centered info, if type == CENTERED_INFO_WARNING
Structure describing the action button in Home Screen.
const nbgl_icon_details_t * icon
icon to use in action button in Home page
nbgl_callback_t callback
function to call when action button is touched in Home page
const char * text
text to use in action button in Home page
nbgl_homeActionStyle_t style
style of action button
nbgl_keyboardButtonsCallback_t updateButtonsCallback
callback to call when a key is pressed to update suggestions
nbgl_layoutTouchCallback_t onButtonCallback
callback to call when one of the buttons is pressed
const char ** buttons
array of strings for buttons (last ones can be NULL)
int firstButtonToken
first token used for buttons, provided in onButtonCallback
Structure containing all parameters for keyboard use case.
keyboardMode_t mode
keyboard mode to start with
nbgl_kbdSuggestParams_t suggestionParams
nbgl_kbdButtonParams_t confirmationParams
used if type is KEYBOARD_WITH_SUGGESTIONS
bool lettersOnly
if true, only display letter keys and Backspace
uint8_t entryMaxLen
maximum length of text that can be entered
nbgl_layoutKeyboardContentType_t type
type of content
const char * title
centered title explaining the screen
char * entryBuffer
already entered text
This structure contains info to build a clickable "bar" with a text and an icon.
const char * text
text (can be NULL)
uint8_t token
the token that will be used as argument of the callback
const char * subText
sub text (can be NULL)
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played
const nbgl_icon_details_t * iconLeft
a buffer containing the 1BPP icon for icon on left (can be NULL)
const nbgl_icon_details_t * iconRight
Structure containing all information when creating a layout. This structure must be passed as argumen...
nbgl_layoutButtonCallback_t onActionCallback
the callback to be called on any action on the layout
This structure contains info to build a keyboard with nbgl_layoutAddKeyboard()
keyboardCallback_t callback
function called when an active key is pressed
This structure contains info to build a keyboard content (controls that are linked to keyboard)
This structure contains info for Text content, to be set with nbgl_layoutAddTextContent().
const char * descriptions[NB_MAX_DESCRIPTIONS]
uint8_t nbDescriptions
number of used descriptions in above array
const char * info
description at bottom (in small gray)
const char * title
main text (in large bold font)
Structure containing all specific information when creating a confirmation page.
const char * cancelText
the text used for cancel action, if NULL a simple X button is used
uint8_t confirmationToken
the token used as argument of the onActionCallback
const char * confirmationText
text of the confirmation button
nbgl_layoutCenteredInfo_t centeredInfo
description of the centered info to be used
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when button is pressed
This structure contains data to build a page in multi-pages mode (nbgl_pageDrawGenericContent)
nbgl_contentTagValueDetails_t tagValueDetails
TAG_VALUE_DETAILS type
const char * title
text for the title of the page (if NULL, no title)
uint8_t topRightToken
token used when top-right button (if not NULL) is touched
nbgl_contentInfoLongPress_t infoLongPress
INFO_LONG_PRESS type
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when title is touched
nbgl_contentBarsList_t barsList
BARS_LIST type
nbgl_contentInfoButton_t infoButton
INFO_BUTTON type
nbgl_contentInfoList_t infosList
INFOS_LIST type
nbgl_contentTagValueList_t tagValueList
TAG_VALUE_LIST type
const nbgl_icon_details_t * topRightIcon
nbgl_contentType_t type
type of page content in the following union
nbgl_contentCenteredInfo_t centeredInfo
CENTERED_INFO type
nbgl_contentTagValueConfirm_t tagValueConfirm
TAG_VALUE_CONFIRM type
bool isTouchableTitle
if set to true, the title is preceded by <- arrow to go back
nbgl_contentExtendedCenter_t extendedCenter
EXTENDED_CENTER type
Structure containing all specific information when creating an information page.
nbgl_layoutButtonStyle_t actionButtonStyle
style of "action" button
const char * actionButtonText
if not NULL an "action" button is set under the centered info
const char * tapActionText
uint8_t bottomButtonsToken
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when button/footer is pressed
const nbgl_icon_details_t * actionButtonIcon
potential icon of "action" button
nbgl_layoutCenteredInfo_t centeredInfo
description of the centered info to be used
Structure containing all specific information when creating a multi-screens page.
uint8_t nbPages
the number of pages to display (if <2, no navigation bar)
uint8_t quitToken
the token used as argument of the actionCallback when the footer is touched
uint8_t skipToken
if skipText is NULL the token used when right part of footer is touched
nbgl_pageNavigationType_t navType
uint8_t activePage
the index of the page to display at start-up
bool progressIndicator
if set to true, display a progress indicator on top of the page
nbgl_pageNavWithButtons_t navWithButtons
structure used when navigation with buttons
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when next or back is pressed
bool visiblePageIndicator
if set to true, the page indicator will be visible in navigation
const char * quitText
the text displayed in footer (on the left), used to quit (only on Flex)
bool backButton
if set to true, a back button (<-) is displayed in the nav bar
This structure contains data to build a SWITCHES_LIST content.
uint8_t nbSwitches
number of elements in switches and tokens array
const nbgl_contentSwitch_t * switches
array of switches (nbSwitches items)
The necessary parameters to build a tip-box in first review page and the modal if this tip box is tou...
const char * text
text of the tip-box
const nbgl_icon_details_t * icon
icon of the tip-box
The necessary parameters to build a warning page preceding a review. One can either use predefinedSet...
const nbgl_preludeDetails_t * prelude
if not null, means that the review can start by a prelude
const nbgl_warningDetails_t * introDetails
const nbgl_warningDetails_t * reviewDetails
Union of the different type of contents.
nbgl_contentInfoList_t infosList
INFOS_LIST type
nbgl_contentInfoLongPress_t infoLongPress
INFO_LONG_PRESS type
nbgl_contentTagValueConfirm_t tagValueConfirm
TAG_VALUE_CONFIRM type
nbgl_contentTagValueList_t tagValueList
TAG_VALUE_LIST type
nbgl_contentCenteredInfo_t centeredInfo
CENTERED_INFO type
nbgl_contentBarsList_t barsList
BARS_LIST type
nbgl_contentExtendedCenter_t extendedCenter
EXTENDED_CENTER type
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
nbgl_contentInfoButton_t infoButton
INFO_BUTTON type
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type