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 reviewWithWarnCtx sharedContext.reviewWithWarning
59#define choiceWithDetailsCtx sharedContext.choiceWithDetails
62#define W3C_DESCRIPTION_MAX_LEN 128
69#define RISKY_OPERATION (1 << 6)
76#define NO_THREAT_OPERATION (1 << 7)
89 ADDRESS_QRCODE_BUTTON_TOKEN,
100 CHOICE_DETAILS_TOKEN,
102 QUIT_TIPBOX_MODAL_TOKEN,
103 WARNING_CHOICE_TOKEN,
105 DISMISS_WARNING_TOKEN,
106 DISMISS_DETAILS_TOKEN,
107 PRELUDE_CHOICE_TOKEN,
108 FIRST_WARN_BAR_TOKEN,
119typedef struct DetailsContext_s {
122 uint8_t currentPairIdx;
126 const char *nextPageStart;
129typedef struct AddressConfirmationContext_s {
133} AddressConfirmationContext_t;
136typedef struct KeypadContext_s {
139 uint8_t pinMinDigits;
140 uint8_t pinMaxDigits;
146typedef struct ReviewWithWarningContext_s {
151 const char *reviewTitle;
152 const char *reviewSubTitle;
153 const char *finishTitle;
158 uint8_t securityReportLevel;
160} ReviewWithWarningContext_t;
162typedef struct ChoiceWithDetailsContext_s {
167} ChoiceWithDetailsContext_t;
171 SHARE_CTX_REVIEW_WITH_WARNING,
172 SHARE_CTX_CHOICE_WITH_DETAILS,
173} SharedContextUsage_t;
180 KeypadContext_t keypad;
182 ReviewWithWarningContext_t reviewWithWarning;
183 ChoiceWithDetailsContext_t choiceWithDetails;
185 SharedContextUsage_t usage;
189 USE_CASE_GENERIC = 0,
191} GenericContextType_t;
194 GenericContextType_t type;
195 uint8_t spinnerPosition;
197 int8_t currentContentIdx;
198 uint8_t currentContentElementNb;
199 uint8_t currentElementIdx;
200 bool hasStartingContent;
201 bool hasFinishingContent;
202 const char *detailsItem;
203 const char *detailsvalue;
204 bool detailsWrapping;
205 bool validWarningCtx;
215 SharedContext_t sharedCtx;
226} nbgl_homeAndSettingsContext_t;
231} nbgl_reviewContext_t;
239} nbgl_reviewStreamingContext_t;
242 nbgl_homeAndSettingsContext_t homeAndSettings;
243 nbgl_reviewContext_t review;
244 nbgl_reviewStreamingContext_t reviewStreaming;
245} nbgl_BundleNavContext_t;
251} SecurityReportItem_t;
258static char tmpString[W3C_DESCRIPTION_MAX_LEN];
278static const char *pageTitle;
281#define activeTipBox genericContext.tipBox
285static bool forwardNavOnly;
286static NavType_t navType;
288static DetailsContext_t detailsContext;
291static AddressConfirmationContext_t addressConfirmationContext;
294static GenericContext_t genericContext;
296 localContentsList[3];
297static uint8_t genericContextPagesInfo[MAX_PAGE_NB / PAGES_PER_UINT8];
298static uint8_t modalContextPagesInfo[MAX_MODAL_PAGE_NB / PAGES_PER_UINT8];
301static nbgl_BundleNavContext_t bundleNavContext;
304static const uint8_t nbMaxElementsPerContentType[] = {
321 .icon = &WARNING_ICON,
322 .text =
"Blind signing required",
323 .subText =
"This transaction's details are not fully verifiable. If "
324 "you sign, you could lose all your assets."
327 .icon = &WARNING_ICON,
328 .text =
"Transaction Check unavailable",
332 .icon = &WARNING_ICON,
333 .text =
"Risk detected",
334 .subText =
"This transaction was scanned as risky by Web3 Checks."
337 .icon = &WARNING_ICON,
338 .text =
"Critical threat",
339 .subText =
"This transaction was scanned as malicious by Web3 Checks."
343 .text =
"No threat detected",
344 .subText =
"Transaction Check didn't find any threat, but always "
345 "review transaction details carefully."
355static char reducedAddress[QRCODE_REDUCED_ADDR_LEN];
361static void displayReviewPage(uint8_t page,
bool forceFullRefresh);
362static void displayDetailsPage(uint8_t page,
bool forceFullRefresh);
363static void displayTagValueListModalPage(uint8_t pageIdx,
bool forceFullRefresh);
364static void displayFullValuePage(
const char *backText,
365 const char *aliasText,
367static void displayInfosListModal(
const char *modalTitle,
371static void displaySettingsPage(uint8_t page,
bool forceFullRefresh);
372static void displayGenericContextPage(uint8_t pageIdx,
bool forceFullRefresh);
373static void pageCallback(
int token, uint8_t index);
375static void displayAddressQRCode(
void);
377static void modalLayoutTouchCallback(
int token, uint8_t index);
378static void displaySkipWarning(
void);
380static void bundleNavStartHome(
void);
381static void bundleNavStartSettingsAtPage(uint8_t initSettingPage);
382static void bundleNavStartSettings(
void);
384static void bundleNavReviewStreamingChoice(
bool confirm);
386static void displaySecurityReport(uint32_t set);
388static void displayInitialWarning(
void);
392 const char *reviewTitle,
393 const char *reviewSubTitle,
394 const char *finishTitle,
398 bool playNotifSound);
401 const char *reviewTitle,
402 const char *reviewSubTitle,
404 bool playNotifSound);
405static void useCaseHomeExt(
const char *appName,
412static void displayDetails(
const char *tag,
const char *value,
bool wrapping);
414static void reset_callbacks_and_context(
void)
421 onContentAction = NULL;
424 onValidatePin = 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;
595 UNUSED(operationType);
601static void pageModalCallback(
int token, uint8_t index)
605 if (token == INFOS_TIP_BOX_TOKEN) {
607 displayFullValuePage(activeTipBox.infos.infoTypes[index],
608 activeTipBox.infos.infoContents[index],
609 &activeTipBox.infos.infoExtensions[index]);
612 else if (token == INFO_ALIAS_TOKEN) {
614 displayFullValuePage(genericContext.currentInfos->infoTypes[index],
615 genericContext.currentInfos->infoContents[index],
616 &genericContext.currentInfos->infoExtensions[index]);
620 modalPageContext = NULL;
621 if (token == NAV_TOKEN) {
628 displayDetailsPage(index,
false);
631 if (token == MODAL_NAV_TOKEN) {
638 displayTagValueListModalPage(index,
false);
641 else if (token == QUIT_TOKEN) {
646 else if (token == QUIT_TIPBOX_MODAL_TOKEN) {
648 if (reviewWithWarnCtx.securityReportLevel == 2) {
649 reviewWithWarnCtx.securityReportLevel = 1;
650 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
658 else if (token == SKIP_TOKEN) {
669 else if (token == CHOICE_TOKEN) {
671 if (onModalConfirm != NULL) {
673 onModalConfirm = NULL;
685static void pageCallback(
int token, uint8_t index)
688 if (token == QUIT_TOKEN) {
689 if (onQuit != NULL) {
693 else if (token == CONTINUE_TOKEN) {
694 if (onContinue != NULL) {
698 else if (token == CHOICE_TOKEN) {
699 if (onChoice != NULL) {
700 onChoice((index == 0) ?
true : false);
703 else if (token == ACTION_BUTTON_TOKEN) {
704 if ((index == 0) && (onAction != NULL)) {
707 else if ((index == 1) && (onQuit != NULL)) {
712 else if (token == ADDRESS_QRCODE_BUTTON_TOKEN) {
713 displayAddressQRCode();
716 else if (token == CONFIRM_TOKEN) {
717 if (onChoice != NULL) {
721 else if (token == REJECT_TOKEN) {
722 if (onChoice != NULL) {
726 else if (token == DETAILS_BUTTON_TOKEN) {
727 displayDetails(genericContext.detailsItem,
728 genericContext.detailsvalue,
729 genericContext.detailsWrapping);
731 else if (token == NAV_TOKEN) {
733 if (onQuit != NULL) {
738 if (navType == GENERIC_NAV || navType == STREAMING_NAV) {
739 displayGenericContextPage(index,
false);
741 else if (navType == REVIEW_NAV) {
742 displayReviewPage(index,
false);
745 displaySettingsPage(index,
false);
749 else if (token == NEXT_TOKEN) {
751 displayReviewPage(navInfo.
activePage + 1,
false);
754 displayGenericContextPage(navInfo.
activePage + 1,
false);
757 else if (token == BACK_TOKEN) {
759 displayReviewPage(navInfo.
activePage - 1,
true);
762 displayGenericContextPage(navInfo.
activePage - 1,
false);
765 else if (token == SKIP_TOKEN) {
767 displaySkipWarning();
769 else if (token == VALUE_ALIAS_TOKEN) {
772 if (genericContext.currentPairs != NULL) {
773 pair = &genericContext.currentPairs[genericContext.currentElementIdx + index];
776 pair = genericContext.currentCallback(genericContext.currentElementIdx + index);
780 else if (token == BLIND_WARNING_TOKEN) {
781 reviewWithWarnCtx.isIntro =
false;
782 reviewWithWarnCtx.warning = NULL;
785 else if (token == WARNING_BUTTON_TOKEN) {
787 reviewWithWarnCtx.securityReportLevel = 1;
789 if (reviewWithWarnCtx.warning->predefinedSet) {
790 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
794 if (reviewWithWarnCtx.isIntro) {
795 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->introDetails);
798 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->reviewDetails);
802 else if (token == TIP_BOX_TOKEN) {
804 if (genericContext.validWarningCtx && (reviewWithWarnCtx.warning->predefinedSet != 0)) {
805 reviewWithWarnCtx.securityReportLevel = 1;
806 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
809 displayInfosListModal(activeTipBox.modalTitle, &activeTipBox.infos,
false);
813 if (onContentAction != NULL) {
814 onContentAction(token, index, navInfo.
activePage);
816 if (onControls != NULL) {
817 onControls(token, index);
823static void tickerCallback(
void)
826 if (onQuit != NULL) {
832static void displaySettingsPage(uint8_t page,
bool forceFullRefresh)
836 if ((onNav == NULL) || (onNav(page, &content) ==
false)) {
841 content.
title = pageTitle;
844 content.
tuneId = TUNE_TAP_CASUAL;
849 if (forceFullRefresh) {
858static void displayReviewPage(uint8_t page,
bool forceFullRefresh)
867 if ((onNav == NULL) || (onNav(navInfo.
activePage, &content) ==
false)) {
872 content.
title = NULL;
874 content.
tuneId = TUNE_TAP_CASUAL;
881 if (forwardNavOnly) {
906 if (forceFullRefresh) {
916static const nbgl_content_t *genericContextComputeNextPageParams(uint8_t pageIdx,
918 uint8_t *p_nbElementsInNextPage,
921 int8_t nextContentIdx = genericContext.currentContentIdx;
922 int16_t nextElementIdx = genericContext.currentElementIdx;
923 uint8_t nbElementsInNextPage;
926 genericContextGetPageInfo(pageIdx, &nbElementsInNextPage, p_flag);
927 *p_nbElementsInNextPage = nbElementsInNextPage;
932 uint8_t nbElementsInCurrentPage;
934 genericContextGetPageInfo(navInfo.
activePage, &nbElementsInCurrentPage, NULL);
935 nextElementIdx += nbElementsInCurrentPage;
940 if ((nextElementIdx >= genericContext.currentContentElementNb)
941 && (genericContext.currentContentElementNb > 0)) {
951 nextElementIdx -= nbElementsInNextPage;
957 if (nextElementIdx < 0) {
959 nextElementIdx = -nbElementsInNextPage;
965 if ((nextContentIdx == -1) && (genericContext.hasStartingContent)) {
966 p_content = &STARTING_CONTENT;
968 else if ((nextContentIdx == genericContext.genericContents.nbContents)
969 && (genericContext.hasFinishingContent)) {
970 p_content = &FINISHING_CONTENT;
973 p_content = getContentAtIdx(&genericContext.genericContents, nextContentIdx, content);
975 if (p_content == NULL) {
990 if ((nextContentIdx != genericContext.currentContentIdx)
991 || (genericContext.currentContentElementNb == 0)) {
992 genericContext.currentContentIdx = nextContentIdx;
993 genericContext.currentContentElementNb = getContentNbElement(p_content);
995 if (nextElementIdx < 0) {
996 nextElementIdx = genericContext.currentContentElementNb + nextElementIdx;
1001 if ((nextElementIdx < 0) || (nextElementIdx >= genericContext.currentContentElementNb)) {
1003 "Invalid element index %d / %d\n",
1005 genericContext.currentContentElementNb);
1010 genericContext.currentElementIdx = nextElementIdx;
1018static bool genericContextPreparePageContent(
const nbgl_content_t *p_content,
1019 uint8_t nbElementsInPage,
1023 uint8_t nextElementIdx = genericContext.currentElementIdx;
1025 pageContent->
title = pageTitle;
1028 pageContent->
tuneId = TUNE_TAP_CASUAL;
1030 pageContent->
type = p_content->
type;
1031 switch (pageContent->
type) {
1083 p_tagValueList = NULL;
1095 genericContext.detailsItem = pair->
item;
1096 genericContext.detailsvalue = pair->
value;
1101 if (p_tagValueList != NULL) {
1102 p_tagValueList->
nbPairs = nbElementsInPage;
1105 p_tagValueList->
pairs
1108 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1110 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1116 p_tagValueList->
pairs = NULL;
1120 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1124 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1140 if ((nextElementIdx + nbElementsInPage)
1152 p_tagValueList->
nbPairs = nbElementsInPage;
1153 p_tagValueList->
pairs
1156 for (uint8_t i = 0; i < nbElementsInPage; i++) {
1158 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
1163 genericContext.currentPairs = p_tagValueList->
pairs;
1164 genericContext.currentCallback = p_tagValueList->
callback;
1188 < nextElementIdx + nbElementsInPage)) {
1208 bool isFirstOrLastPage
1212 = (navType == STREAMING_NAV)
1213 ? bundleNavContext.reviewStreaming.operationType
1214 : ((navType == GENERIC_NAV) ? bundleNavContext.review.operationType : 0);
1217 if (isFirstOrLastPage
1218 && (operationType & (
BLIND_OPERATION | RISKY_OPERATION | NO_THREAT_OPERATION))) {
1220 if ((operationType & NO_THREAT_OPERATION)
1229 = (operationType &
BLIND_OPERATION) ? BLIND_WARNING_TOKEN : WARNING_BUTTON_TOKEN;
1236static void displayGenericContextPage(uint8_t pageIdx,
bool forceFullRefresh)
1240 uint8_t nbElementsInPage;
1244 if (navType == STREAMING_NAV) {
1246 if (bundleNavContext.reviewStreaming.skipCallback != NULL) {
1247 bundleNavContext.reviewStreaming.skipCallback();
1251 else if (pageIdx >= bundleNavContext.reviewStreaming.stepPageNb) {
1252 bundleNavReviewStreamingChoice(
true);
1259 pageIdx = navInfo.
nbPages - 1;
1265 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1270 for (
int i = navInfo.
activePage + 1; i <= pageIdx; i++) {
1271 p_content = genericContextComputeNextPageParams(i, &content, &nbElementsInPage, &flag);
1281 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1284 if (p_content == NULL) {
1288 if ((navType != STREAMING_NAV)
1291 if ((pageIdx > 0) && (pageIdx < (navInfo.
nbPages - 1))) {
1303 if (!genericContextPreparePageContent(p_content, nbElementsInPage, flag, &pageContent)) {
1309 if (forceFullRefresh) {
1318static const char *getDetailsPageAt(uint8_t detailsPage)
1321 const char *currentChar = detailsContext.value;
1322 while (page < detailsPage) {
1332 detailsContext.wrapping);
1334 if (currentChar[len] ==
'\n') {
1337 else if (detailsContext.wrapping ==
false) {
1340 currentChar = currentChar + len;
1348static void displayDetailsPage(uint8_t detailsPage,
bool forceFullRefresh)
1352 .nbPages = detailsContext.nbPages,
1354 .quitToken = QUIT_TOKEN,
1355 .navWithButtons.navToken = NAV_TOKEN,
1356 .navWithButtons.quitButton =
true,
1357 .navWithButtons.backButton =
true,
1358 .navWithButtons.quitText = NULL,
1359 .progressIndicator =
false,
1360 .tuneId = TUNE_TAP_CASUAL};
1362 .topRightIcon = NULL,
1363 .tagValueList.nbPairs = 1,
1364 .tagValueList.pairs = ¤tPair,
1365 .tagValueList.smallCaseForValue =
true,
1366 .tagValueList.wrapping = detailsContext.wrapping};
1368 if (modalPageContext != NULL) {
1371 currentPair.
item = detailsContext.tag;
1373 if (detailsPage <= detailsContext.currentPage) {
1375 currentPair.
value = getDetailsPageAt(detailsPage);
1376 forceFullRefresh =
true;
1380 currentPair.
value = detailsContext.nextPageStart;
1382 detailsContext.currentPage = detailsPage;
1393 detailsContext.wrapping);
1396 if (currentPair.
value[len] ==
'\n') {
1399 else if (!detailsContext.wrapping) {
1404 detailsContext.nextPageStart = currentPair.
value + len;
1410 detailsContext.nextPageStart = NULL;
1419 if (forceFullRefresh) {
1428static void displayFullValuePage(
const char *backText,
1429 const char *aliasText,
1432 const char *modalTitle
1433 = (extension->
backText != NULL) ? PIC(extension->
backText) : PIC(backText);
1435 genericContext.currentInfos = extension->
infolist;
1436 displayInfosListModal(modalTitle, extension->
infolist,
true);
1439 genericContext.currentTagValues = extension->
tagValuelist;
1444 .withLeftBorder =
true,
1445 .onActionCallback = &modalLayoutTouchCallback,
1446 .tapActionText = NULL};
1448 .separationLine =
false,
1449 .backAndText.token = 0,
1450 .backAndText.tuneId = TUNE_TAP_CASUAL,
1451 .backAndText.text = modalTitle};
1460 .text1 = (extension->
title != NULL) ? extension->
title : extension->fullValue,
1461 .text2 = extension->explanation,
1472 info =
"ENS names are resolved by Ledger backend.";
1475 info =
"This account label comes from your Address Book in Ledger Wallet.";
1481 genericContext.modalLayout, aliasText, extension->
fullValue, info);
1490static void displayInfosListModal(
const char *modalTitle,
1497 .quitToken = QUIT_TIPBOX_MODAL_TOKEN,
1498 .navWithButtons.navToken = NAV_TOKEN,
1499 .navWithButtons.quitButton =
false,
1500 .navWithButtons.backButton =
true,
1501 .navWithButtons.quitText = NULL,
1502 .progressIndicator =
false,
1503 .tuneId = TUNE_TAP_CASUAL};
1506 .topRightIcon = NULL,
1507 .infosList.nbInfos = infos->
nbInfos,
1509 .infosList.infoTypes = infos->
infoTypes,
1512 .infosList.token = fromReview ? INFO_ALIAS_TOKEN : INFOS_TIP_BOX_TOKEN,
1513 .
title = modalTitle,
1514 .titleToken = QUIT_TIPBOX_MODAL_TOKEN,
1515 .tuneId = TUNE_TAP_CASUAL};
1517 if (modalPageContext != NULL) {
1526static void displayTagValueListModalPage(uint8_t pageIdx,
bool forceFullRefresh)
1529 .nbPages = detailsContext.nbPages,
1531 .quitToken = QUIT_TOKEN,
1532 .navWithButtons.navToken = MODAL_NAV_TOKEN,
1533 .navWithButtons.quitButton =
true,
1534 .navWithButtons.backButton =
true,
1535 .navWithButtons.quitText = NULL,
1536 .progressIndicator =
false,
1537 .tuneId = TUNE_TAP_CASUAL};
1539 .topRightIcon = NULL,
1540 .tagValueList.smallCaseForValue =
true,
1541 .tagValueList.wrapping = detailsContext.wrapping};
1542 uint8_t nbElementsInPage;
1545 if (detailsContext.currentPage <= pageIdx) {
1546 modalContextGetPageInfo(pageIdx, &nbElementsInPage);
1550 modalContextGetPageInfo(pageIdx + 1, &nbElementsInPage);
1551 detailsContext.currentPairIdx -= nbElementsInPage;
1552 modalContextGetPageInfo(pageIdx, &nbElementsInPage);
1553 detailsContext.currentPairIdx -= nbElementsInPage;
1555 detailsContext.currentPage = pageIdx;
1558 = &genericContext.currentTagValues->pairs[detailsContext.currentPairIdx];
1560 detailsContext.currentPairIdx += nbElementsInPage;
1566 if (modalPageContext != NULL) {
1571 if (forceFullRefresh) {
1580static void displayAddressQRCode(
void)
1584 .withLeftBorder =
true,
1585 .onActionCallback = &modalLayoutTouchCallback,
1586 .tapActionText = NULL};
1588 .
type =
HEADER_EMPTY, .separationLine =
false, .emptySpace.height = SMALL_CENTERING_HEADER};
1594 addressConfirmationContext.modalLayout =
nbgl_layoutGet(&layoutDescription);
1599 addressConfirmationContext.tagValuePairs[0].value,
1603 if (nbLines <= QRCODE_NB_MAX_LINES) {
1604 qrCode.
text2 = addressConfirmationContext.tagValuePairs[0].value;
1609 addressConfirmationContext.tagValuePairs[0].value,
1611 QRCODE_NB_MAX_LINES,
1613 QRCODE_REDUCED_ADDR_LEN);
1614 qrCode.
text2 = reducedAddress;
1620 addressConfirmationContext.modalLayout,
"Close", DISMISS_QR_TOKEN, TUNE_TAP_CASUAL);
1628static void modalLayoutTouchCallback(
int token, uint8_t index)
1631 if (token == DISMISS_QR_TOKEN) {
1634 addressConfirmationContext.modalLayout = NULL;
1637 else if (token == DISMISS_WARNING_TOKEN) {
1641 if (reviewWithWarnCtx.securityReportLevel <= 1) {
1642 reviewWithWarnCtx.modalLayout = NULL;
1647 reviewWithWarnCtx.securityReportLevel = 1;
1649 if (reviewWithWarnCtx.warning->predefinedSet) {
1650 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
1655 = (reviewWithWarnCtx.isIntro) ? reviewWithWarnCtx.warning->introDetails
1656 : reviewWithWarnCtx.warning->reviewDetails;
1657 displayCustomizedSecurityReport(details);
1662 else if (token == DISMISS_DETAILS_TOKEN) {
1666 if (choiceWithDetailsCtx.level <= 1) {
1667 choiceWithDetailsCtx.modalLayout = NULL;
1672 choiceWithDetailsCtx.level = 1;
1673 choiceWithDetailsCtx.modalLayout
1674 = displayModalDetails(choiceWithDetailsCtx.details, DISMISS_DETAILS_TOKEN);
1677 else if ((token >= FIRST_WARN_BAR_TOKEN) && (token <= LAST_WARN_BAR_TOKEN)) {
1678 if (sharedContext.usage == SHARE_CTX_REVIEW_WITH_WARNING) {
1681 reviewWithWarnCtx.securityReportLevel = 2;
1683 if (reviewWithWarnCtx.warning->predefinedSet) {
1684 displaySecurityReport(1 << (token - FIRST_WARN_BAR_TOKEN));
1689 = (reviewWithWarnCtx.isIntro) ? reviewWithWarnCtx.warning->introDetails
1690 : reviewWithWarnCtx.warning->reviewDetails;
1692 displayCustomizedSecurityReport(
1697 else if (sharedContext.usage == SHARE_CTX_CHOICE_WITH_DETAILS) {
1699 = &choiceWithDetailsCtx.details->
barList.
details[token - FIRST_WARN_BAR_TOKEN];
1703 choiceWithDetailsCtx.level = 2;
1704 choiceWithDetailsCtx.modalLayout
1705 = displayModalDetails(details, DISMISS_DETAILS_TOKEN);
1713 genericContext.modalLayout = NULL;
1720static void layoutTouchCallback(
int token, uint8_t index)
1723 if (token == WARNING_CHOICE_TOKEN) {
1725 reviewWithWarnCtx.choiceCallback(
false);
1728 reviewWithWarnCtx.isIntro =
false;
1729 if (reviewWithWarnCtx.isStreaming) {
1730 useCaseReviewStreamingStart(reviewWithWarnCtx.operationType,
1731 reviewWithWarnCtx.icon,
1732 reviewWithWarnCtx.reviewTitle,
1733 reviewWithWarnCtx.reviewSubTitle,
1734 reviewWithWarnCtx.choiceCallback,
1738 useCaseReview(reviewWithWarnCtx.operationType,
1739 reviewWithWarnCtx.tagValueList,
1740 reviewWithWarnCtx.icon,
1741 reviewWithWarnCtx.reviewTitle,
1742 reviewWithWarnCtx.reviewSubTitle,
1743 reviewWithWarnCtx.finishTitle,
1745 reviewWithWarnCtx.choiceCallback,
1752 else if (token == WARNING_BUTTON_TOKEN) {
1754 reviewWithWarnCtx.securityReportLevel = 1;
1756 if (reviewWithWarnCtx.warning->predefinedSet) {
1757 displaySecurityReport(reviewWithWarnCtx.warning->predefinedSet);
1762 ? reviewWithWarnCtx.warning->introDetails
1763 : reviewWithWarnCtx.warning->reviewDetails;
1764 displayCustomizedSecurityReport(details);
1768 else if (token == CHOICE_DETAILS_TOKEN) {
1769 choiceWithDetailsCtx.level = 1;
1770 choiceWithDetailsCtx.modalLayout
1771 = displayModalDetails(choiceWithDetailsCtx.details, DISMISS_DETAILS_TOKEN);
1774 else if (token == PRELUDE_CHOICE_TOKEN) {
1776 displayCustomizedSecurityReport(reviewWithWarnCtx.warning->prelude->details);
1780 displayInitialWarning();
1783 reviewWithWarnCtx.isIntro =
false;
1784 if (reviewWithWarnCtx.isStreaming) {
1785 useCaseReviewStreamingStart(reviewWithWarnCtx.operationType,
1786 reviewWithWarnCtx.icon,
1787 reviewWithWarnCtx.reviewTitle,
1788 reviewWithWarnCtx.reviewSubTitle,
1789 reviewWithWarnCtx.choiceCallback,
1793 useCaseReview(reviewWithWarnCtx.operationType,
1794 reviewWithWarnCtx.tagValueList,
1795 reviewWithWarnCtx.icon,
1796 reviewWithWarnCtx.reviewTitle,
1797 reviewWithWarnCtx.reviewSubTitle,
1798 reviewWithWarnCtx.finishTitle,
1800 reviewWithWarnCtx.choiceCallback,
1808 else if (token == CHOICE_TOKEN) {
1809 if (onChoice != NULL) {
1810 onChoice((index == 0) ?
true : false);
1816static void displaySkipWarning(
void)
1819 .cancelText =
"Go back to review",
1820 .centeredInfo.text1 =
"Skip review?",
1822 =
"If you're sure you don't need to review all fields, you can skip straight to signing.",
1823 .centeredInfo.text3 = NULL,
1825 .centeredInfo.icon = &IMPORTANT_CIRCLE_ICON,
1826 .centeredInfo.offsetY = 0,
1827 .confirmationText =
"Yes, skip",
1828 .confirmationToken = SKIP_TOKEN,
1829 .
tuneId = TUNE_TAP_CASUAL,
1831 if (modalPageContext != NULL) {
1843static void updateKeyPad(
bool add)
1845 bool enableValidate, enableBackspace, enableDigits;
1846 bool redrawKeypad =
false;
1849 enableDigits = (keypadContext.pinLen < keypadContext.pinMaxDigits);
1850 enableValidate = (keypadContext.pinLen >= keypadContext.pinMinDigits);
1851 enableBackspace = (keypadContext.pinLen > 0);
1853 if ((keypadContext.pinLen == keypadContext.pinMinDigits)
1855 (keypadContext.pinLen == keypadContext.pinMaxDigits)
1857 (keypadContext.pinLen == 1)) {
1858 redrawKeypad =
true;
1862 if ((keypadContext.pinLen == 0) ||
1863 (keypadContext.pinLen == (keypadContext.pinMinDigits - 1))
1865 (keypadContext.pinLen
1866 == (keypadContext.pinMaxDigits - 1))) {
1867 redrawKeypad =
true;
1870 if (keypadContext.hidden ==
true) {
1875 keypadContext.layoutCtx,
false, 0, (
const char *) keypadContext.pinEntry);
1879 keypadContext.layoutCtx, 0, enableValidate, enableBackspace, enableDigits);
1882 if ((!add) && (keypadContext.pinLen == 0)) {
1890static void keypadCallback(
char touchedKey)
1892 switch (touchedKey) {
1894 if (keypadContext.pinLen > 0) {
1895 keypadContext.pinLen--;
1896 keypadContext.pinEntry[keypadContext.pinLen] = 0;
1898 updateKeyPad(
false);
1907 onValidatePin(keypadContext.pinEntry, keypadContext.pinLen);
1911 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1912 if (keypadContext.pinLen < keypadContext.pinMaxDigits) {
1913 keypadContext.pinEntry[keypadContext.pinLen] = touchedKey;
1914 keypadContext.pinLen++;
1922static void keypadGeneric_cb(
int token, uint8_t index)
1925 if (token != BACK_TOKEN) {
1946static uint8_t getNbTagValuesInPage(uint8_t nbPairs,
1950 bool hasConfirmationButton,
1951 bool hasDetailsButton,
1952 bool *requireSpecificDisplay)
1954 uint8_t nbPairsInPage = 0;
1955 uint16_t currentHeight = PRE_TAG_VALUE_MARGIN;
1961 maxUsableHeight -= TOUCHABLE_HEADER_BAR_HEIGHT - SMALL_CENTERING_HEADER;
1964 *requireSpecificDisplay =
false;
1965 while (nbPairsInPage < nbPairs) {
1972 if (nbPairsInPage > 0) {
1973 currentHeight += INTER_TAG_VALUE_MARGIN;
1976 if (tagValueList->
pairs != NULL) {
1977 pair = PIC(&tagValueList->
pairs[startIndex + nbPairsInPage]);
1980 pair = PIC(tagValueList->
callback(startIndex + nbPairsInPage));
1989 if (nbPairsInPage > 0) {
1996 *requireSpecificDisplay =
true;
2008 value_font = SMALL_REGULAR_FONT;
2011 value_font = LARGE_MEDIUM_FONT;
2020 if (nbPairsInPage == 0) {
2024 *requireSpecificDisplay =
true;
2033 if (hasConfirmationButton && (nbPairsInPage == nbPairs)) {
2034 maxUsableHeight -= UP_FOOTER_BUTTON_HEIGHT;
2035 if (currentHeight > maxUsableHeight) {
2040 else if (hasDetailsButton) {
2041 maxUsableHeight -= (SMALL_BUTTON_RADIUS * 2);
2042 if (currentHeight > maxUsableHeight) {
2046 return nbPairsInPage;
2058static uint8_t getNbTagValuesInDetailsPage(uint8_t nbPairs,
2062 uint8_t nbPairsInPage = 0;
2063 uint16_t currentHeight = PRE_TAG_VALUE_MARGIN;
2066 while (nbPairsInPage < nbPairs) {
2071 if (nbPairsInPage > 0) {
2072 currentHeight += INTER_TAG_VALUE_MARGIN;
2075 if (tagValueList->
pairs != NULL) {
2076 pair = PIC(&tagValueList->
pairs[startIndex + nbPairsInPage]);
2079 pair = PIC(tagValueList->
callback(startIndex + nbPairsInPage));
2093 if (currentHeight >= maxUsableHeight) {
2098 return nbPairsInPage;
2101static uint8_t getNbPagesForContent(
const nbgl_content_t *content,
2102 uint8_t pageIdxStart,
2106 uint8_t nbElements = 0;
2107 uint8_t nbPages = 0;
2108 uint8_t nbElementsInPage;
2109 uint8_t elemIdx = 0;
2112 nbElements = getContentNbElement(content);
2114 while (nbElements > 0) {
2117 bool hasNav = !isLast || (pageIdxStart > 0) || (elemIdx > 0);
2119 nbElementsInPage = getNbTagValuesInPage(nbElements,
2128 nbElementsInPage = getNbTagValuesInPage(nbElements,
2153 nbElementsInPage =
MIN(nbMaxElementsPerContentType[content->
type], nbElements);
2156 elemIdx += nbElementsInPage;
2157 genericContextSetPageInfo(pageIdxStart + nbPages, nbElementsInPage, flag);
2158 nbElements -= nbElementsInPage;
2166 uint8_t pageIdxStart,
2169 uint8_t nbPages = 0;
2173 for (
int i = 0; i < genericContents->
nbContents; i++) {
2174 p_content = getContentAtIdx(genericContents, i, &content);
2175 if (p_content == NULL) {
2178 nbPages += getNbPagesForContent(p_content,
2179 pageIdxStart + nbPages,
2187static void prepareAddressConfirmationPages(
const char *address,
2194 addressConfirmationContext.tagValuePairs[0].item =
"Address";
2195 addressConfirmationContext.tagValuePairs[0].value = address;
2196 addressConfirmationContext.nbPairs = 1;
2205 if ((tagValueList != NULL) && (tagValueList->
nbPairs < ADDR_VERIF_NB_PAIRS)) {
2209 for (uint8_t i = 0; i < tagValueList->
nbPairs; i++) {
2210 memcpy(&addressConfirmationContext.tagValuePairs[1 + i],
2211 &tagValueList->
pairs[i],
2213 addressConfirmationContext.nbPairs++;
2217 tmpList.
nbPairs = addressConfirmationContext.nbPairs;
2218 tmpList.
pairs = addressConfirmationContext.tagValuePairs;
2219 addressConfirmationContext.nbPairs = getNbTagValuesInPage(
2220 addressConfirmationContext.nbPairs, &tmpList, 0,
false,
true,
true, &flag);
2222 if (tmpList.
nbPairs > addressConfirmationContext.nbPairs) {
2223 addressConfirmationContext.nbPairs = 1;
2234 tagValueConfirm->
tuneId = TUNE_TAP_CASUAL;
2242 if ((tagValueList != NULL)
2243 && (tagValueList->
nbPairs > (addressConfirmationContext.nbPairs - 1))) {
2253 tagValueConfirm->
tuneId = TUNE_TAP_CASUAL;
2256 = tagValueList->
nbPairs - (addressConfirmationContext.nbPairs - 1);
2258 = &tagValueList->
pairs[addressConfirmationContext.nbPairs - 1];
2267static void bundleNavStartHome(
void)
2269 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
2271 useCaseHomeExt(context->appName,
2274 context->settingContents != NULL ?
true : false,
2275 &context->homeAction,
2276 bundleNavStartSettings,
2277 context->quitCallback);
2280static void bundleNavStartSettingsAtPage(uint8_t initSettingPage)
2282 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
2286 context->settingContents,
2288 bundleNavStartHome);
2291static void bundleNavStartSettings(
void)
2293 bundleNavStartSettingsAtPage(0);
2296static void bundleNavReviewConfirmRejection(
void)
2298 bundleNavContext.review.choiceCallback(
false);
2305 const char *confirmText;
2310 title =
"Reject transaction?";
2311 confirmText =
"Go back to transaction";
2314 title =
"Reject message?";
2315 confirmText =
"Go back to message";
2318 title =
"Reject operation?";
2319 confirmText =
"Go back to operation";
2326static void bundleNavReviewChoice(
bool confirm)
2329 bundleNavContext.review.choiceCallback(
true);
2332 bundleNavReviewAskRejectionConfirmation(bundleNavContext.review.operationType,
2333 bundleNavReviewConfirmRejection);
2337static void bundleNavReviewStreamingConfirmRejection(
void)
2339 bundleNavContext.reviewStreaming.choiceCallback(
false);
2342static void bundleNavReviewStreamingChoice(
bool confirm)
2345 bundleNavContext.reviewStreaming.choiceCallback(
true);
2348 bundleNavReviewAskRejectionConfirmation(bundleNavContext.reviewStreaming.operationType,
2349 bundleNavReviewStreamingConfirmRejection);
2359 .withLeftBorder =
true,
2360 .onActionCallback = modalLayoutTouchCallback,
2361 .tapActionText = NULL};
2363 .separationLine =
true,
2364 .backAndText.icon = NULL,
2365 .backAndText.tuneId = TUNE_TAP_CASUAL,
2366 .backAndText.token = token};
2382 bar.
token = FIRST_WARN_BAR_TOKEN + i;
2383 bar.
tuneId = TUNE_TAP_CASUAL;
2410static void displaySecurityReport(uint32_t set)
2413 .withLeftBorder =
true,
2414 .onActionCallback = modalLayoutTouchCallback,
2415 .tapActionText = NULL};
2417 .separationLine =
true,
2418 .backAndText.icon = NULL,
2419 .backAndText.tuneId = TUNE_TAP_CASUAL,
2420 .backAndText.token = DISMISS_WARNING_TOKEN};
2424 const char *provider;
2426 reviewWithWarnCtx.modalLayout =
nbgl_layoutGet(&layoutDescription);
2432 if ((reviewWithWarnCtx.securityReportLevel == 1) && (!reviewWithWarnCtx.isIntro)) {
2436 && (reviewWithWarnCtx.warning->predefinedSet & (1 << i))) {
2439 || (reviewWithWarnCtx.warning->providerMessage == NULL)) {
2440 bar.
subText = securityReportItems[i].subText;
2443 bar.
subText = reviewWithWarnCtx.warning->providerMessage;
2445 bar.
text = securityReportItems[i].text;
2448 bar.
token = FIRST_WARN_BAR_TOKEN + i;
2449 bar.
tuneId = TUNE_TAP_CASUAL;
2454 bar.
iconLeft = securityReportItems[i].icon;
2465 if (reviewWithWarnCtx.warning && reviewWithWarnCtx.warning->reportProvider) {
2466 provider = reviewWithWarnCtx.warning->reportProvider;
2469 provider =
"[unknown]";
2475 + W3C_DESCRIPTION_MAX_LEN / 2;
2479 .text1 = reviewWithWarnCtx.warning->reportUrl,
2480 .text2 =
"Scan to view full report",
2485 W3C_DESCRIPTION_MAX_LEN / 2,
2487 reviewWithWarnCtx.warning->reportUrl);
2488 urlLen = strlen(destStr) + 1;
2493 snprintf(destStr + urlLen, W3C_DESCRIPTION_MAX_LEN / 2 - urlLen,
"%s report", provider);
2499 info.
icon = &LARGE_WARNING_ICON;
2500 info.
title =
"This transaction cannot be Clear Signed";
2502 =
"This transaction or message cannot be decoded fully. If you choose to sign, you "
2503 "could be authorizing malicious actions that can drain your wallet.\n\nLearn more: "
2512 info.
icon = &LARGE_WARNING_ICON;
2513 info.
title =
"Transaction Check unavailable";
2515 =
"If you're not using the Ledger Wallet app, Transaction Check might not work. If "
2517 "are using Ledger Wallet, reject the transaction and try again.\n\nGet help at "
2536 reviewWithWarnCtx.modalLayout = displayModalDetails(details, DISMISS_WARNING_TOKEN);
2540static void displayInitialWarning(
void)
2543#ifdef HAVE_PIEZO_SOUND
2544 tune_index_e tune = TUNE_RESERVED;
2548 .token = WARNING_CHOICE_TOKEN,
2549 .topText =
"Back to safety",
2551 .tuneId = TUNE_TAP_CASUAL};
2553 .separationLine =
false,
2554 .emptySpace.height = MEDIUM_CENTERING_HEADER};
2555 uint32_t set = reviewWithWarnCtx.warning->predefinedSet
2558 bool isBlindSigningOnly
2560 reviewWithWarnCtx.isIntro =
true;
2562 layoutDescription.
modal =
false;
2568 layoutDescription.
ticker.tickerCallback = NULL;
2569 reviewWithWarnCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
2572 if (reviewWithWarnCtx.warning->predefinedSet != 0) {
2575 isBlindSigningOnly ? &INFO_I_ICON : &QRCODE_ICON,
2576 WARNING_BUTTON_TOKEN,
2579 else if (reviewWithWarnCtx.warning->introTopRightIcon != NULL) {
2581 reviewWithWarnCtx.warning->introTopRightIcon,
2582 WARNING_BUTTON_TOKEN,
2587 if (reviewWithWarnCtx.warning->predefinedSet != 0) {
2590 const char *provider;
2593 info.
icon = &LARGE_WARNING_ICON;
2596 if (isBlindSigningOnly ==
false) {
2597 if (reviewWithWarnCtx.warning->reportProvider) {
2598 provider = reviewWithWarnCtx.warning->reportProvider;
2601 provider =
"[unknown]";
2604 snprintf(tmpString, W3C_DESCRIPTION_MAX_LEN,
"Detected by %s", provider);
2608 if (isBlindSigningOnly) {
2609 info.
title =
"Blind signing ahead";
2612 =
"If you sign this transaction, you could loose all your assets. "
2613 "Explore safer alternatives: ledger.com/integrated-apps";
2614 buttonsInfo.
bottomText =
"Accept risk and continue";
2618 =
"This transaction's details are not fully verifiable. If you sign, you could "
2619 "lose all your assets.";
2622#ifdef HAVE_PIEZO_SOUND
2623 tune = TUNE_NEUTRAL;
2627 info.
title =
"Potential risk";
2628 if (reviewWithWarnCtx.warning->providerMessage == NULL) {
2632 info.
description = reviewWithWarnCtx.warning->providerMessage;
2634 buttonsInfo.
bottomText =
"Accept risk and continue";
2635#ifdef HAVE_PIEZO_SOUND
2636 tune = TUNE_NEUTRAL;
2640 info.
title =
"Critical threat";
2641 if (reviewWithWarnCtx.warning->providerMessage == NULL) {
2645 info.
description = reviewWithWarnCtx.warning->providerMessage;
2647 buttonsInfo.
bottomText =
"Accept threat and continue";
2648#ifdef HAVE_PIEZO_SOUND
2654 else if (reviewWithWarnCtx.warning->info != NULL) {
2657#ifdef HAVE_PIEZO_SOUND
2658 tune = TUNE_LOOK_AT_ME;
2664#ifdef HAVE_PIEZO_SOUND
2665 if (tune != TUNE_RESERVED) {
2666 os_io_seph_cmd_piezo_play_tune(tune);
2674static void displayPrelude(
void)
2678 = {.
bottomText = reviewWithWarnCtx.warning->prelude->footerText,
2679 .token = PRELUDE_CHOICE_TOKEN,
2680 .topText = reviewWithWarnCtx.warning->prelude->buttonText,
2682 .tuneId = TUNE_TAP_CASUAL};
2684 .separationLine =
false,
2685 .emptySpace.height = MEDIUM_CENTERING_HEADER};
2687 reviewWithWarnCtx.isIntro =
true;
2689 layoutDescription.
modal =
false;
2693 layoutDescription.
ticker.tickerCallback = NULL;
2694 reviewWithWarnCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
2701 info.
icon = reviewWithWarnCtx.warning->prelude->icon;
2703 info.
title = reviewWithWarnCtx.warning->prelude->title;
2704 info.
description = reviewWithWarnCtx.warning->prelude->description;
2710#ifdef HAVE_PIEZO_SOUND
2711 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
2720 const char *predefinedTipBoxText = NULL;
2723 if (reviewWithWarnCtx.warning) {
2724 if (reviewWithWarnCtx.warning->predefinedSet & (1 <<
W3C_ISSUE_WARN)) {
2726 predefinedTipBoxText =
"Transaction Check unavailable.\nBlind signing required.";
2729 predefinedTipBoxText =
"Transaction Check unavailable";
2734 predefinedTipBoxText =
"Critical threat detected.\nBlind signing required.";
2737 predefinedTipBoxText =
"Critical threat detected.";
2742 predefinedTipBoxText =
"Potential risk detected.\nBlind signing required.";
2745 predefinedTipBoxText =
"Potential risk detected.";
2750 predefinedTipBoxText
2751 =
"No threat detected by Transaction Check but blind signing required.";
2754 predefinedTipBoxText =
"No threat detected by Transaction Check.";
2758 predefinedTipBoxText =
"Blind signing required.";
2762 if ((tipBox != NULL) || (predefinedTipBoxText != NULL)) {
2764 STARTING_CONTENT.content.extendedCenter.contentCenter.subText = NULL;
2765 if (predefinedTipBoxText != NULL) {
2766 genericContext.validWarningCtx =
true;
2767 STARTING_CONTENT.content.extendedCenter.tipBox.icon = NULL;
2768 STARTING_CONTENT.content.extendedCenter.tipBox.text = predefinedTipBoxText;
2771 STARTING_CONTENT.content.extendedCenter.tipBox.icon = tipBox->
icon;
2772 STARTING_CONTENT.content.extendedCenter.tipBox.text = tipBox->
text;
2774 STARTING_CONTENT.content.extendedCenter.tipBox.token = TIP_BOX_TOKEN;
2775 STARTING_CONTENT.content.extendedCenter.tipBox.tuneId = TUNE_TAP_CASUAL;
2783 const char *reviewTitle,
2784 const char *reviewSubTitle,
2785 const char *finishTitle,
2789 bool playNotifSound)
2791 bundleNavContext.review.operationType = operationType;
2792 bundleNavContext.review.choiceCallback = choiceCallback;
2795 onChoice = bundleNavReviewChoice;
2796 navType = GENERIC_NAV;
2799 genericContext.genericContents.contentsList = localContentsList;
2800 genericContext.genericContents.nbContents = 3;
2805 prepareReviewFirstPage(
2806 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
2809 initWarningTipBox(tipBox);
2813 memcpy(&localContentsList[1].content.tagValueList,
2821 prepareReviewLightLastPage(
2822 operationType, &localContentsList[2].content.infoButton, icon, finishTitle);
2826 prepareReviewLastPage(
2827 operationType, &localContentsList[2].content.infoLongPress, icon, finishTitle);
2831 uint8_t nbPages = getNbPagesForGenericContents(
2833 prepareNavInfo(
true, nbPages, getRejectReviewText(operationType));
2836 if (playNotifSound) {
2837#ifdef HAVE_PIEZO_SOUND
2838 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
2842 displayGenericContextPage(0,
true);
2848 const char *reviewTitle,
2849 const char *reviewSubTitle,
2851 bool playNotifSound)
2853 bundleNavContext.reviewStreaming.operationType = operationType;
2854 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
2855 bundleNavContext.reviewStreaming.icon = icon;
2858 onChoice = bundleNavReviewStreamingChoice;
2859 navType = STREAMING_NAV;
2862 genericContext.genericContents.contentsList = localContentsList;
2863 genericContext.genericContents.nbContents = 1;
2868 prepareReviewFirstPage(
2869 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
2872 initWarningTipBox(NULL);
2875 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
2882 if (playNotifSound) {
2883#ifdef HAVE_PIEZO_SOUND
2884 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
2888 displayGenericContextPage(0,
true);
2907static void useCaseHomeExt(
const char *appName,
2909 const char *tagline,
2916 .centeredInfo.text1 = appName,
2917 .centeredInfo.text3 = NULL,
2919 .centeredInfo.offsetY = 0,
2922 .tapActionText = NULL,
2924 .topRightToken = CONTINUE_TOKEN,
2925 .tuneId = TUNE_TAP_CASUAL};
2926 reset_callbacks_and_context();
2928 if ((homeAction->
text != NULL) || (homeAction->
icon != NULL)) {
2943 if (tagline == NULL) {
2947 "This app enables signing\ntransactions on its network.");
2974 onContinue = topRightCallback;
2975 onQuit = quitCallback;
2989static void displayDetails(
const char *tag,
const char *value,
bool wrapping)
2991 memset(&detailsContext, 0,
sizeof(detailsContext));
2997 detailsContext.tag = tag;
2998 detailsContext.value = value;
3000 detailsContext.currentPage = 0;
3001 detailsContext.wrapping = wrapping;
3003 if (detailsContext.nbPages > 1) {
3004 uint16_t nbLostChars = (detailsContext.nbPages - 1) * 3;
3007 uint8_t nbLinesInLastPage
3013 detailsContext.nbPages++;
3017 displayDetailsPage(0,
true);
3023 uint8_t nbElements = 0;
3024 uint8_t nbElementsInPage;
3025 uint8_t elemIdx = 0;
3028 memset(&detailsContext, 0,
sizeof(detailsContext));
3029 nbElements = tagValues->
nbPairs;
3031 while (nbElements > 0) {
3032 nbElementsInPage = getNbTagValuesInDetailsPage(nbElements, tagValues, elemIdx);
3034 elemIdx += nbElementsInPage;
3035 modalContextSetPageInfo(detailsContext.nbPages, nbElementsInPage);
3036 nbElements -= nbElementsInPage;
3037 detailsContext.nbPages++;
3040 displayTagValueListModalPage(0,
true);
3062 bool *requireSpecificDisplay)
3064 return getNbTagValuesInPage(
3065 nbPairs, tagValueList, startIndex,
false,
false,
false, requireSpecificDisplay);
3085 bool *requireSpecificDisplay)
3087 return getNbTagValuesInPage(
3088 nbPairs, tagValueList, startIndex, isSkippable,
false,
false, requireSpecificDisplay);
3105 uint8_t nbInfosInPage = 0;
3106 uint16_t currentHeight = 0;
3107 uint16_t previousHeight;
3108 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3109 const char *
const *infoContents = PIC(infosList->
infoContents);
3111 while (nbInfosInPage < nbInfos) {
3114 += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING + LIST_ITEM_HEADING_SUB_TEXT;
3118 PIC(infoContents[startIndex + nbInfosInPage]),
3125 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3130 previousHeight = currentHeight;
3133 return nbInfosInPage;
3150 uint8_t nbSwitchesInPage = 0;
3151 uint16_t currentHeight = 0;
3152 uint16_t previousHeight = 0;
3153 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3156 while (nbSwitchesInPage < nbSwitches) {
3160 uint16_t textHeight =
MAX(
3161 LIST_ITEM_MIN_TEXT_HEIGHT,
3163 currentHeight += textHeight + 2 * LIST_ITEM_PRE_HEADING;
3166 currentHeight += LIST_ITEM_HEADING_SUB_TEXT;
3176 previousHeight = currentHeight;
3181 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3184 return nbSwitchesInPage;
3201 uint8_t nbBarsInPage = 0;
3202 uint16_t currentHeight = 0;
3203 uint16_t previousHeight;
3204 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3209 while (nbBarsInPage < nbBars) {
3210 currentHeight += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING;
3215 previousHeight = currentHeight;
3220 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3223 return nbBarsInPage;
3240 uint8_t nbChoicesInPage = 0;
3241 uint16_t currentHeight = 0;
3242 uint16_t previousHeight;
3243 uint16_t navHeight = withNav ? SIMPLE_FOOTER_HEIGHT : 0;
3245 UNUSED(choicesList);
3248 while (nbChoicesInPage < nbChoices) {
3249 currentHeight += LIST_ITEM_MIN_TEXT_HEIGHT + 2 * LIST_ITEM_PRE_HEADING;
3254 if (!withNav && (previousHeight >= (
INFOS_AREA_HEIGHT - SIMPLE_FOOTER_HEIGHT))) {
3259 previousHeight = currentHeight;
3262 return nbChoicesInPage;
3273 uint8_t nbPages = 0;
3274 uint8_t nbPairs = tagValueList->
nbPairs;
3275 uint8_t nbPairsInPage;
3279 while (i < tagValueList->nbPairs) {
3283 nbPairs -= nbPairsInPage;
3295 const char *tagline,
3302 appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
3311 const char *tagline,
3313 const char *actionButtonText,
3321 .text = actionButtonText};
3324 appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
3347 reset_callbacks_and_context();
3350 onQuit = quitCallback;
3351 onNav = navCallback;
3352 onControls = controlsCallback;
3354 navType = SETTINGS_NAV;
3357 prepareNavInfo(
false, nbPages, NULL);
3359 displaySettingsPage(initPage,
true);
3377 title, initPage, nbPages, quitCallback, navCallback, controlsCallback);
3398 reset_callbacks_and_context();
3401 onQuit = quitCallback;
3402 pageTitle = appName;
3403 navType = GENERIC_NAV;
3405 if (settingContents != NULL) {
3408 if (infosList != NULL) {
3409 genericContext.hasFinishingContent =
true;
3412 memcpy(&FINISHING_CONTENT.content, infosList,
sizeof(
nbgl_content_u));
3416 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
3417 if (infosList != NULL) {
3418 nbPages += getNbPagesForContent(&FINISHING_CONTENT, nbPages,
true,
false);
3421 prepareNavInfo(
false, nbPages, NULL);
3423 displayGenericContextPage(initPage,
true);
3462 const char *appName,
3464 const char *tagline,
3472 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
3474 reset_callbacks_and_context();
3476 context->appName = appName;
3477 context->appIcon = appIcon;
3478 context->tagline = tagline;
3479 context->settingContents = settingContents;
3480 context->infosList = infosList;
3481 if (action != NULL) {
3487 context->quitCallback = quitCallback;
3490 bundleNavStartSettingsAtPage(initSettingPage);
3493 bundleNavStartHome();
3507 .tickerIntervale = 0,
3511 reset_callbacks_and_context();
3513 onQuit = quitCallback;
3515#ifdef HAVE_PIEZO_SOUND
3516 os_io_seph_cmd_piezo_play_tune(TUNE_LEDGER_MOMENT);
3519 info.
centeredInfo.
icon = isSuccess ? &CHECK_CIRCLE_ICON : &DENIED_CIRCLE_ICON;
3524 info.
tuneId = TUNE_TAP_CASUAL;
3540 switch (reviewStatusType) {
3542 msg =
"Operation signed";
3546 msg =
"Operation rejected";
3550 msg =
"Transaction signed";
3554 msg =
"Transaction rejected";
3558 msg =
"Message signed";
3562 msg =
"Message rejected";
3566 msg =
"Address verified";
3570 msg =
"Address verification\ncancelled";
3592 const char *message,
3593 const char *subMessage,
3594 const char *confirmText,
3595 const char *cancelText,
3600 if ((confirmText == NULL) || (cancelText == NULL)) {
3603 reset_callbacks_and_context();
3612 info.
tuneId = TUNE_TAP_CASUAL;
3614 onChoice = callback;
3634 const char *message,
3635 const char *subMessage,
3636 const char *confirmText,
3637 const char *cancelText,
3643 .token = CHOICE_TOKEN,
3644 .topText = confirmText,
3646 .tuneId = TUNE_TAP_CASUAL};
3649 .separationLine =
false,
3650 .emptySpace.height = MEDIUM_CENTERING_HEADER};
3653 if ((confirmText == NULL) || (cancelText == NULL)) {
3657 reset_callbacks_and_context();
3659 onChoice = callback;
3660 layoutDescription.
modal =
false;
3666 layoutDescription.
ticker.tickerCallback = NULL;
3667 sharedContext.usage = SHARE_CTX_CHOICE_WITH_DETAILS;
3668 choiceWithDetailsCtx.layoutCtx =
nbgl_layoutGet(&layoutDescription);
3669 choiceWithDetailsCtx.details = details;
3673 centeredInfo.
icon = icon;
3674 centeredInfo.
title = message;
3678 if (details != NULL) {
3680 choiceWithDetailsCtx.layoutCtx, &SEARCH_ICON, CHOICE_DETAILS_TOKEN, TUNE_TAP_CASUAL);
3701 const char *subMessage,
3702 const char *confirmText,
3703 const char *cancelText,
3709 .centeredInfo.text1 = message,
3710 .centeredInfo.text2 = subMessage,
3711 .centeredInfo.text3 = NULL,
3713 .centeredInfo.icon = &IMPORTANT_CIRCLE_ICON,
3714 .centeredInfo.offsetY = 0,
3715 .confirmationText = confirmText,
3716 .confirmationToken = CHOICE_TOKEN,
3717 .tuneId = TUNE_TAP_CASUAL,
3719 onModalConfirm = callback;
3720 if (modalPageContext != NULL) {
3738 const char *message,
3739 const char *actionText,
3744 reset_callbacks_and_context();
3746 onAction = callback;
3748 content.
tuneId = TUNE_TAP_CASUAL;
3771 const char *reviewTitle,
3772 const char *reviewSubTitle,
3773 const char *rejectText,
3778 .footerToken = QUIT_TOKEN,
3779 .tapActionText = NULL,
3780 .isSwipeable =
true,
3781 .tapActionToken = CONTINUE_TOKEN,
3783 .actionButtonText = NULL,
3784 .
tuneId = TUNE_TAP_CASUAL};
3786 reset_callbacks_and_context();
3794 onQuit = rejectCallback;
3795 onContinue = continueCallback;
3797#ifdef HAVE_PIEZO_SOUND
3799 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
3812 const char *rejectText,
3817 reset_callbacks_and_context();
3820 onChoice = choiceCallback;
3821 onNav = navCallback;
3822 onControls = buttonCallback;
3823 forwardNavOnly =
false;
3824 navType = REVIEW_NAV;
3828 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
3830 displayReviewPage(initPage,
true);
3847 const char *rejectText,
3852 reset_callbacks_and_context();
3855 onChoice = callback;
3856 navType = GENERIC_NAV;
3860 genericContext.genericContents.contentsList = localContentsList;
3863 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
3865 memcpy(&localContentsList[offset].content.tagValueList,
3872 memcpy(&localContentsList[offset].content.infoLongPress,
3878 genericContext.genericContents.nbContents = offset;
3881 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
3883 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
3885 displayGenericContextPage(0,
true);
3903 const char *rejectText,
3908 reset_callbacks_and_context();
3911 onChoice = callback;
3912 navType = GENERIC_NAV;
3915 genericContext.genericContents.contentsList = localContentsList;
3918 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
3920 memcpy(&localContentsList[offset].content.tagValueList,
3934 genericContext.genericContents.nbContents = offset;
3937 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
3939 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
3941 displayGenericContextPage(0,
true);
3963 const char *reviewTitle,
3964 const char *reviewSubTitle,
3965 const char *finishTitle,
3968 reset_callbacks_and_context();
3970 useCaseReview(operationType,
4004 const char *reviewTitle,
4005 const char *reviewSubTitle,
4006 const char *finishTitle,
4017 &blindSigningWarning,
4046 const char *reviewTitle,
4047 const char *reviewSubTitle,
4048 const char *finishTitle,
4053 reset_callbacks_and_context();
4056 if (tipBox != NULL) {
4057 memcpy(&activeTipBox, tipBox,
sizeof(activeTipBox));
4060 if ((warning == NULL)
4063 useCaseReview(operationType,
4076 operationType |= NO_THREAT_OPERATION;
4079 operationType |= RISKY_OPERATION;
4081 sharedContext.usage = SHARE_CTX_REVIEW_WITH_WARNING;
4082 reviewWithWarnCtx.isStreaming =
false;
4083 reviewWithWarnCtx.operationType = operationType;
4084 reviewWithWarnCtx.tagValueList = tagValueList;
4085 reviewWithWarnCtx.icon = icon;
4086 reviewWithWarnCtx.reviewTitle = reviewTitle;
4087 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
4088 reviewWithWarnCtx.finishTitle = finishTitle;
4089 reviewWithWarnCtx.warning = warning;
4090 reviewWithWarnCtx.choiceCallback = choiceCallback;
4093 if (reviewWithWarnCtx.warning->prelude) {
4098 displayInitialWarning();
4101 useCaseReview(operationType,
4133 const char *reviewTitle,
4134 const char *reviewSubTitle,
4135 const char *finishTitle,
4138 reset_callbacks_and_context();
4140 useCaseReview(operationType,
4161 const char *rejectText,
4164 reset_callbacks_and_context();
4167 onQuit = rejectCallback;
4168 navType = GENERIC_NAV;
4175 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4176 prepareNavInfo(
true, nbPages, rejectText);
4179#ifdef HAVE_PIEZO_SOUND
4181 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4184 displayGenericContextPage(0,
true);
4201 const char *reviewTitle,
4202 const char *reviewSubTitle,
4205 reset_callbacks_and_context();
4207 useCaseReviewStreamingStart(
4208 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4226 const char *reviewTitle,
4227 const char *reviewSubTitle,
4231 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
4251 const char *reviewTitle,
4252 const char *reviewSubTitle,
4256 reset_callbacks_and_context();
4259 if ((warning == NULL)
4262 useCaseReviewStreamingStart(
4263 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4267 operationType |= NO_THREAT_OPERATION;
4270 operationType |= RISKY_OPERATION;
4273 sharedContext.usage = SHARE_CTX_REVIEW_WITH_WARNING;
4274 reviewWithWarnCtx.isStreaming =
true;
4275 reviewWithWarnCtx.operationType = operationType;
4276 reviewWithWarnCtx.icon = icon;
4277 reviewWithWarnCtx.reviewTitle = reviewTitle;
4278 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
4279 reviewWithWarnCtx.choiceCallback = choiceCallback;
4280 reviewWithWarnCtx.warning = warning;
4283 if (reviewWithWarnCtx.warning->prelude) {
4288 displayInitialWarning();
4291 useCaseReviewStreamingStart(
4292 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
4314 memset(&genericContext, 0,
sizeof(genericContext));
4316 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
4317 bundleNavContext.reviewStreaming.skipCallback = skipCallback;
4320 onChoice = bundleNavReviewStreamingChoice;
4321 navType = STREAMING_NAV;
4324 genericContext.genericContents.contentsList = localContentsList;
4325 genericContext.genericContents.nbContents = 1;
4334 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
4335 &genericContext.genericContents,
4338 prepareNavInfo(
true,
4340 getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
4348 displayGenericContextPage(0,
true);
4379 memset(&genericContext, 0,
sizeof(genericContext));
4381 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
4384 onChoice = bundleNavReviewStreamingChoice;
4385 navType = STREAMING_NAV;
4388 genericContext.genericContents.contentsList = localContentsList;
4389 genericContext.genericContents.nbContents = 1;
4394 prepareReviewLastPage(bundleNavContext.reviewStreaming.operationType,
4395 &STARTING_CONTENT.content.infoLongPress,
4396 bundleNavContext.reviewStreaming.icon,
4400 bundleNavContext.reviewStreaming.stepPageNb = getNbPagesForGenericContents(
4401 &genericContext.genericContents,
4404 prepareNavInfo(
true, 1, getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
4406 displayGenericContextPage(0,
true);
4417 reset_callbacks_and_context();
4418 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
4421 onChoice = callback;
4422 navType = GENERIC_NAV;
4425 genericContext.genericContents.contentsList = localContentsList;
4426 genericContext.genericContents.nbContents = (tagValueList == NULL) ? 1 : 2;
4428 prepareAddressConfirmationPages(
4429 address, tagValueList, &STARTING_CONTENT, &localContentsList[1]);
4432 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4434 prepareNavInfo(
true, nbPages,
"Cancel");
4436#ifdef HAVE_PIEZO_SOUND
4438 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4441 displayGenericContextPage(0,
true);
4463 const char *reviewTitle,
4464 const char *reviewSubTitle,
4467 reset_callbacks_and_context();
4470 if (addressConfirmationContext.modalLayout) {
4473 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
4476 onChoice = choiceCallback;
4477 navType = GENERIC_NAV;
4481 genericContext.genericContents.contentsList = localContentsList;
4486 prepareReviewFirstPage(
4487 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
4488 STARTING_CONTENT.content.extendedCenter.contentCenter.subText =
"Swipe to continue";
4491 prepareAddressConfirmationPages(
4492 address, additionalTagValueList, &localContentsList[1], &localContentsList[2]);
4495 genericContext.genericContents.nbContents
4497 uint8_t nbPages = getNbPagesForGenericContents(&genericContext.genericContents, 0,
false);
4499 prepareNavInfo(
true, nbPages,
"Cancel");
4501#ifdef HAVE_PIEZO_SOUND
4503 os_io_seph_cmd_piezo_play_tune(TUNE_LOOK_AT_ME);
4506 displayGenericContextPage(0,
true);
4520 if (genericContext.type != USE_CASE_SPINNER) {
4521 memset(&genericContext, 0,
sizeof(genericContext));
4522 genericContext.type = USE_CASE_SPINNER;
4527 genericContext.backgroundLayout =
nbgl_layoutGet(&layoutDescription);
4530 genericContext.backgroundLayout, text, NULL, genericContext.spinnerPosition);
4537 genericContext.spinnerPosition++;
4540 genericContext.spinnerPosition = 0;
4543 genericContext.backgroundLayout, text, NULL, genericContext.spinnerPosition);
4547 else if (ret == 2) {
4582 .separationLine =
true,
4583 .backAndText.token = BACK_TOKEN,
4584 .backAndText.tuneId = TUNE_TAP_CASUAL,
4585 .backAndText.text = NULL};
4592 reset_callbacks_and_context();
4594 memset(&keypadContext, 0,
sizeof(KeypadContext_t));
4597 onQuit = backCallback;
4601 layoutDescription.
modal =
false;
4604 keypadContext.hidden = hidden;
4616 keypadContext.layoutCtx, title, keypadContext.hidden, maxDigits,
"");
4623 onValidatePin = validatePinCallback;
4625 keypadContext.pinMinDigits = minDigits;
4626 keypadContext.pinMaxDigits = maxDigits;
nbgl_contentTagValue_t *(* nbgl_contentTagValueCallback_t)(uint8_t pairIndex)
prototype of tag/value pair retrieval callback
@ ICON_ILLUSTRATION
simple icon
@ LARGE_CASE_INFO
text in BLACK and large case (INTER 32px), subText in black in Inter24px
@ 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_DEBUG(__logger,...)
bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t maxNbLines, uint16_t *len, bool wrapping)
compute the len of the given text (in bytes) fitting in the given maximum nb lines,...
void nbgl_textReduceOnNbLines(nbgl_font_id_e fontId, const char *origText, uint16_t maxWidth, uint8_t nbLines, char *reducedText, uint16_t reducedTextLen)
Create a reduced version of given ASCII text to wrap it on the given max width (in pixels),...
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
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)
Creates an area on the center of the main panel, with a possible icon, and possible texts under it.
int nbgl_layoutAddTextContent(nbgl_layout_t *layout, const char *title, const char *description, const char *info)
Creates in the main container three text areas:
int nbgl_layoutUpdateKeypad(nbgl_layout_t *layout, uint8_t index, bool enableValidate, bool enableBackspace, bool enableDigits)
Updates an existing keypad on bottom of the screen, with the given configuration.
int nbgl_layoutAddSeparationLine(nbgl_layout_t *layout)
adds a separation line on bottom of the last added item
int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info)
Creates an area on the center of the main panel, with a QRCode, a possible text in black (bold) under...
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout)
Creates a touchable bar in main panel.
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
@ BLACK_BACKGROUND
rounded bordered button, with text/icon in white, on black background
int nbgl_layoutAddTopRightButton(nbgl_layout_t *layout, const nbgl_icon_details_t *icon, uint8_t token, tune_index_e tuneId)
Creates a Top-right button in the top right corner of the top panel.
void * nbgl_layout_t
type shared externally
@ HEADER_EMPTY
empty space, to have a better vertical centering of centered info
@ HEADER_BACK_AND_TEXT
back key and optional text
int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, const char *title, 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...
#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
int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_t *footerDesc)
Creates a touchable area at the footer of the screen, containing various controls,...
@ ROUNDED_AND_FOOTER_STYLE
A black background button on top of a footer.
int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info)
Creates two buttons to make a choice. Both buttons are mandatory. Both buttons are full width,...
int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, const char *subText, uint8_t initPosition)
Creates a centered (vertically & horizontally) spinner with a text under it.
int nbgl_layoutUpdateSpinner(nbgl_layout_t *layout, const char *text, const char *subText, uint8_t position)
Update an existing spinner (must be the only object of the layout)
#define NBGL_NO_PROGRESS_INDICATOR
To be used when a control token shall not be used.
int nbgl_layoutAddHeader(nbgl_layout_t *layout, const nbgl_layoutHeader_t *headerDesc)
Creates a touchable (or not) area at the header of the screen, containing various controls,...
@ FOOTER_EMPTY
empty space, to have a better vertical centering of centered info
int nbgl_layoutRelease(nbgl_layout_t *layout)
Release the layout obtained with nbgl_layoutGet()
int nbgl_layoutAddFooter(nbgl_layout_t *layout, const char *text, uint8_t token, tune_index_e tuneId)
Creates a touchable text at the footer of the screen, separated with a thin line from the rest of the...
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
#define NB_SPINNER_POSITIONS
void nbgl_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
#define KEYPAD_MAX_DIGITS
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
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)
draw a generic content page, with the given content, and if nav parameter is not NULL,...
nbgl_page_t * nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_screenTickerConfiguration_t *ticker, const nbgl_pageInfoDescription_t *info)
draw a page with a centered info (icon and/or texts) with a touchable footer, in a potential "tapable...
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)
draw a confirmation page, with a centered info (icon and/or text), a button to confirm and a footer t...
int nbgl_pageRelease(nbgl_page_t *)
Release the page obtained with any of the nbgl_pageDrawXXX() functions.
nbgl_page_t * nbgl_pageDrawGenericContentExt(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageNavigationInfo_t *nav, nbgl_pageContent_t *content, bool modal)
draw a generic content page, with the given content, and if nav parameter is not NULL,...
@ 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)
This function redraws the whole screen on top of stack and its children.
@ 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()
@ 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.
DEPRECATED void nbgl_useCaseHome(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, bool withSettings, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback)
#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
DEPRECATED void nbgl_useCaseSettings(const char *settingsTitle, uint8_t initPage, uint8_t nbPages, bool touchableTitle, nbgl_callback_t quitCallback, nbgl_navCallback_t navCallback, nbgl_layoutTouchCallback_t controlsCallback)
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.
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)
DEPRECATED void nbgl_useCaseRegularReview(uint8_t initPage, uint8_t nbPages, const char *rejectText, nbgl_layoutTouchCallback_t buttonCallback, nbgl_navCallback_t navCallback, nbgl_choiceCallback_t choiceCallback)
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)
void nbgl_useCaseStaticReviewLight(const nbgl_contentTagValueList_t *tagValueList, const nbgl_pageInfoLongPress_t *infoLongPress, const char *rejectText, nbgl_choiceCallback_t callback)
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)
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_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
void nbgl_useCaseReviewStart(const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *rejectText, nbgl_callback_t continueCallback, nbgl_callback_t rejectCallback)
DEPRECATED void nbgl_useCaseHomeExt(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, bool withSettings, const char *actionButtonText, nbgl_callback_t actionCallback, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback)
#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)
DEPRECATED void nbgl_useCaseAddressConfirmationExt(const char *address, nbgl_choiceCallback_t callback, const nbgl_contentTagValueList_t *tagValueList)
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 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_useCaseStaticReview(const nbgl_contentTagValueList_t *tagValueList, const nbgl_pageInfoLongPress_t *infoLongPress, const char *rejectText, nbgl_choiceCallback_t callback)
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)
#define REAL_TYPE_MASK
This is the mask to apply on nbgl_operationType_t to get the real type provided by app.
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,...
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
int16_t offsetY
vertical shift to apply to this info (if >0, shift to bottom)
const char * text3
third text (can be null)
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
int8_t centeredInfo
if set to 1, the tag will be displayed as a centered info
const char * value
string giving the value name
const char * item
string giving the tag name
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 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_layoutQRCode_t qrCode
QR code, if type == QRCODE_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
This structure contains info to build a clickable "bar" with a text and an icon.
bool inactive
if set to true, the bar is grayed-out and cannot be touched
const char * text
text (can be NULL)
uint8_t token
the token that will be used as argument of the callback
bool large
set to true only for the main level of OS settings
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_screenTickerConfiguration_t ticker
const char * tapActionText
Light gray text used when main container is "tapable".
nbgl_layoutTouchCallback_t onActionCallback
the callback to be called on any action on the layout
This structure contains info to build a centered (vertically and horizontally) area,...
const char * text2
second text (can be null)
const char * url
URL for QR code.
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