18#include "os_helpers.h"
29typedef struct ReviewContext_s {
33 const char *reviewTitle;
34 const char *reviewSubTitle;
35 const char *finishTitle;
40 uint8_t dataDirection;
41 uint8_t currentTagValueIndex;
42 uint8_t currentExtensionPage;
43 uint8_t nbExtensionPages;
49typedef struct ChoiceContext_s {
52 const char *subMessage;
53 const char *confirmText;
54 const char *cancelText;
59typedef struct ConfirmContext_s {
61 const char *subMessage;
62 const char *confirmText;
63 const char *cancelText;
68typedef struct ContentContext_s {
71 const char *rejectText;
77typedef struct HomeContext_s {
87typedef struct ActionContext_s {
92typedef struct KeypadContext_s {
106typedef struct KeyboardContext_s {
109 uint16_t entryMaxLen;
111 uint8_t keyboardIndex;
124 GENERIC_REVIEW_USE_CASE,
125 ADDRESS_REVIEW_USE_CASE,
126 STREAMING_START_REVIEW_USE_CASE,
127 STREAMING_CONTINUE_REVIEW_USE_CASE,
128 STREAMING_FINISH_REVIEW_USE_CASE,
142typedef struct UseCaseContext_s {
147 uint8_t firstPairPage;
152 ReviewContext_t review;
153 ChoiceContext_t choice;
154 ConfirmContext_t confirm;
156 ContentContext_t content;
158 KeypadContext_t keypad;
161 KeyboardContext_t keyboard;
163 ActionContext_t action;
167typedef struct PageContent_s {
181typedef struct ReviewWithWarningContext_s {
186 const char *reviewTitle;
187 const char *reviewSubTitle;
188 const char *finishTitle;
191 uint8_t securityReportLevel;
194 uint8_t nbWarningPages;
195 uint8_t firstWarningPage;
196 uint8_t barDetailIdx;
197} ReviewWithWarningContext_t;
208static UseCaseContext_t context;
210static ReviewWithWarningContext_t reviewWithWarnCtx;
228static void displaySpinner(
const char *text);
230static void startUseCaseHome(
void);
231static void startUseCaseInfo(
void);
232static void startUseCaseSettings(
void);
233static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
234static void startUseCaseContent(
void);
236static void statusTickerCallback(
void);
239static void displayWarningStep(
void);
244 switch (content->
type) {
274 if (contentIdx >= genericContents->
nbContents) {
280 if (content == NULL) {
286 if (context.content.navCallback) {
287 if (context.content.navCallback(contentIdx, &pageContent) ==
true) {
290 switch (content->
type) {
339 uint8_t *elemContentIdx,
345 uint8_t elemNbPages = 0;
347 switch (context.type) {
348 case SETTINGS_USE_CASE:
350 case GENERIC_SETTINGS:
351 genericContents = context.home.settingContents;
353 case CONTENT_USE_CASE:
354 case GENERIC_REVIEW_USE_CASE:
355 genericContents = &context.content.genericContents;
360 for (
unsigned int i = 0; i < genericContents->
nbContents; i++) {
361 p_content = getContentAtIdx(genericContents, i, content);
362 elemNbPages = getContentNbElement(p_content);
363 if (nbPages + elemNbPages > elemIdx) {
364 *elemContentIdx = context.currentPage - nbPages;
367 nbPages += elemNbPages;
373static const char *getChoiceName(uint8_t choiceIndex)
383 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
384 if (p_content == NULL) {
386 "getChoiceName(): p_content is NULL for page %d\n",
387 context.currentPage);
390 switch (p_content->
type) {
393 names = (
char **) PIC(contentChoices->
names);
398 names = (
char **) PIC(contentBars->
barTexts);
399 nbValues = contentBars->
nbBars;
405 if (choiceIndex >= nbValues) {
409 return (
const char *) PIC(names[choiceIndex]);
412static void onChoiceSelected(uint8_t choiceIndex)
421 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
422 if (p_content == NULL) {
424 "onChoiceSelected(): p_content is NULL for page %d\n",
425 context.currentPage);
428 switch (p_content->
type) {
431 if (choiceIndex < contentChoices->nbChoices) {
432 token = contentChoices->
token;
437 if (choiceIndex < contentBars->nbBars) {
438 token = ((
const uint8_t *) PIC(contentBars->
tokens))[choiceIndex];
454 if (context.content.controlsCallback != NULL) {
455 context.content.controlsCallback(token, choiceIndex);
463 if ((context.type == GENERIC_SETTINGS) && (context.home.quitCallback != NULL)) {
464 context.home.quitCallback();
467 if (context.type == SETTINGS_USE_CASE) {
471 if (context.content.quitCallback != NULL) {
472 context.content.quitCallback();
482 bool *isCenteredInfo)
486 if (tagValueList->
pairs != NULL) {
487 pair = PIC(&tagValueList->
pairs[index]);
490 pair = PIC(tagValueList->
callback(index));
493 *value = pair->
value;
498 *isCenteredInfo =
true;
506static void onReviewAccept(
void)
508 if (context.review.onChoice) {
509 context.review.onChoice(
true);
513static void onReviewReject(
void)
515 if (context.review.onChoice) {
516 context.review.onChoice(
false);
520static void onChoiceAccept(
void)
522 if (context.choice.onChoice) {
523 context.choice.onChoice(
true);
527static void onChoiceReject(
void)
529 if (context.choice.onChoice) {
530 context.choice.onChoice(
false);
534static void onConfirmAccept(
void)
536 if (context.confirm.currentStep) {
539 if (context.confirm.onConfirm) {
540 context.confirm.onConfirm();
544static void onConfirmReject(
void)
546 if (context.confirm.currentStep) {
553static void onSwitchAction(
void)
560 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
563 "onSwitchAction(): p_content is NULL or not a switches list for page %d\n",
564 context.currentPage);
569 switch (context.type) {
570 case SETTINGS_USE_CASE:
572 case GENERIC_SETTINGS:
575 case CONTENT_USE_CASE:
576 case GENERIC_REVIEW_USE_CASE:
586 context.currentPage);
588 else if (context.content.controlsCallback != NULL) {
589 context.content.controlsCallback(contentSwitch->
token, 0);
599 ForcedType_t forcedType,
611 .tickerIntervale = 0,
617 if ((context.type == STREAMING_CONTINUE_REVIEW_USE_CASE)
618 && (context.review.skipCallback != NULL) && (context.review.nbDataSets > 1)) {
621 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
624 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
629 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
631 switch (p_content->
type) {
653 else if ((icon == NULL) && (forcedType != FORCE_CENTERED_INFO)) {
655 if (subTxt != NULL) {
661 newStep =
nbgl_stepDrawText(pos, onActionCallback, p_ticker, txt, subTxt, style, modal);
669 if ((subTxt != NULL) || (context.stepCallback != NULL) || context.forceAction) {
677 if (context.type == CONFIRM_USE_CASE) {
678 context.confirm.currentStep = newStep;
684 const char *description,
693 switchInfo.
text = title;
694 switchInfo.
subText = description;
707 if (context.currentPage > 0) {
708 context.currentPage--;
712 else if ((context.type != STREAMING_CONTINUE_REVIEW_USE_CASE)
713 || (context.review.skipCallback == NULL) || (context.review.nbDataSets == 1)) {
720 if (context.currentPage < (
int) (context.nbPages - 1)) {
721 context.currentPage++;
731 if (context.stepCallback != NULL) {
732 context.stepCallback();
734 else if ((context.type == CONTENT_USE_CASE) || (context.type == SETTINGS_USE_CASE)
735 || (context.type == GENERIC_SETTINGS)
736 || (context.type == GENERIC_REVIEW_USE_CASE)) {
737 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
738 if (p_content != NULL) {
739 switch (p_content->
type) {
753 token = ((
const uint8_t *) PIC(
764 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
773 bool used_action_callback
775 ContextType_t prev_type = context.type;
776 if (used_action_callback) {
781 else if (context.content.controlsCallback != NULL) {
782 context.content.controlsCallback(token, index);
788 if (context.type != prev_type) {
801 if (used_action_callback
819 if (!buttonGenericCallback(event, &pos)) {
824 context.review.dataDirection = pos;
826 displayReviewPage(pos);
838 && (context.currentPage > context.firstPairPage)) {
839 context.currentPage--;
846 && (context.currentPage < (
int) (context.nbPages - 1))
847 && (context.currentPage > context.firstPairPage)) {
848 context.currentPage++;
854 if (context.firstPairPage == 0) {
856 context.review.skipCallback();
860 context.currentPage = context.nbPages - 2;
869 if (context.firstPairPage == 0) {
870 displayStreamingReviewPage(pos);
873 displayReviewPage(pos);
883 context.action.actionCallback();
892 if (!buttonGenericCallback(event, &pos)) {
897 context.review.dataDirection = pos;
900 displayStreamingReviewPage(pos);
908 if (!buttonGenericCallback(event, &pos)) {
912 displaySettingsPage(pos,
false);
920 if (!buttonGenericCallback(event, &pos)) {
924 displayInfoPage(pos);
932 if (!buttonGenericCallback(event, &pos)) {
936 displayHomePage(pos);
944 if (!buttonGenericCallback(event, &pos)) {
948 displayChoicePage(pos);
956 if (!buttonGenericCallback(event, &pos)) {
969 if (context.stepCallback != NULL) {
970 context.stepCallback();
980 if (!buttonGenericCallback(event, &pos)) {
984 displayContent(pos,
false);
988static void statusTickerCallback(
void)
990 if (context.stepCallback != NULL) {
991 context.stepCallback();
1003 if (context.review.currentExtensionPage > 0) {
1004 context.review.currentExtensionPage--;
1010 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
1011 context.review.currentExtensionPage++;
1017 if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
1027 displayExtensionStep(pos);
1036 const char *text = NULL;
1037 const char *subText = NULL;
1039 if (context.review.extensionStepCtx != NULL) {
1042 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
1043 if (context.review.currentExtensionPage == 0) {
1050 switch (context.review.extension->aliasType) {
1052 text = context.review.extension->title;
1053 subText = context.review.extension->fullValue;
1056 bool has_scope = (context.review.extension->aliasSubName != NULL);
1057 bool has_tn = (context.review.extension->explanation != NULL);
1058 uint8_t page = context.review.currentExtensionPage;
1060 text = context.review.extension->title;
1061 subText = has_scope ? context.review.extension->aliasSubName
1062 : context.review.extension->fullValue;
1064 else if (has_scope && page == 1) {
1065 text = context.review.extension->title;
1066 subText = context.review.extension->fullValue;
1069 text = context.review.extension->explanation;
1074 infoList = context.review.extension->infolist;
1075 text = PIC(infoList->
infoTypes[context.review.currentExtensionPage]);
1076 subText = PIC(infoList->
infoContents[context.review.currentExtensionPage]);
1079 tagValueList = context.review.extension->tagValuelist;
1080 text = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
item);
1081 subText = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
value);
1091 else if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
1093 info.
icon = &C_icon_back_x;
1094 info.
text1 =
"Back";
1097 context.review.extensionStepCtx
1103static void displayAliasFullValue(
void)
1105 const char *text = NULL;
1106 const char *subText = NULL;
1108 bool isCenteredInfo;
1110 getPairData(context.review.tagValueList,
1111 context.review.currentTagValueIndex,
1114 &context.review.extension,
1117 if (context.review.extension == NULL) {
1120 "displayAliasFullValue: extension nor found for pair %d\n",
1121 context.review.currentTagValueIndex);
1124 context.review.currentExtensionPage = 0;
1125 context.review.extensionStepCtx = NULL;
1127 switch (context.review.extension->aliasType) {
1129 context.review.nbExtensionPages = 2;
1132 context.review.nbExtensionPages
1133 = 2 + ((context.review.extension->aliasSubName != NULL) ? 1 : 0)
1134 + ((context.review.extension->explanation != NULL) ? 1 : 0);
1137 context.review.nbExtensionPages = context.review.extension->infolist->nbInfos + 1;
1140 context.review.nbExtensionPages = context.review.extension->tagValuelist->nbPairs + 1;
1144 "displayAliasFullValue: unsupported alias type %d\n",
1145 context.review.extension->aliasType);
1151static void getLastPageInfo(
bool approve,
const nbgl_icon_details_t **icon,
const char **text)
1155 *icon = &C_icon_validate_14;
1157 if ((context.type == REVIEW_USE_CASE) && (context.review.finishTitle != NULL)) {
1158 *text = context.review.finishTitle;
1161 *text =
"Confirm contact details";
1164 else if (context.type == ADDRESS_REVIEW_USE_CASE) {
1169 if (context.review.finishTitle != NULL) {
1170 *text = context.review.finishTitle;
1176 *text =
"Accept risk and sign transaction";
1179 *text =
"Sign transaction";
1184 *text =
"Accept risk and sign message";
1187 *text =
"Sign message";
1192 *text =
"Accept risk and sign operation";
1195 *text =
"Sign operation";
1201 context.stepCallback = onReviewAccept;
1205 *icon = &C_icon_crossmark;
1206 if ((context.type == ADDRESS_REVIEW_USE_CASE)
1211 *text =
"Reject transaction";
1214 *text =
"Reject message";
1217 *text =
"Reject operation";
1219 context.stepCallback = onReviewReject;
1226 uint8_t reviewPages = 0;
1227 uint8_t finalPages = 0;
1228 uint8_t pairIndex = 0;
1229 const char *text = NULL;
1230 const char *subText = NULL;
1232 uint8_t currentIndex = 0;
1233 uint8_t titleIndex = 255;
1234 uint8_t subIndex = 255;
1235 uint8_t approveIndex = 255;
1236 uint8_t rejectIndex = 255;
1238 ForcedType_t forcedType = NO_FORCED_TYPE;
1240 context.stepCallback = NULL;
1244 titleIndex = currentIndex++;
1246 if (context.review.reviewSubTitle) {
1248 subIndex = currentIndex++;
1251 approveIndex = context.nbPages - 2;
1252 rejectIndex = context.nbPages - 1;
1253 finalPages = approveIndex;
1256 if (context.currentPage >= finalPages) {
1257 if (context.currentPage == approveIndex) {
1259 getLastPageInfo(
true, &icon, &text);
1261 else if (context.currentPage == rejectIndex) {
1263 getLastPageInfo(
false, &icon, &text);
1266 else if (context.currentPage < reviewPages) {
1267 if (context.currentPage == titleIndex) {
1269 icon = context.review.icon;
1270 text = context.review.reviewTitle;
1272 else if (context.currentPage == subIndex) {
1274 text = context.review.reviewSubTitle;
1277 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
1280 subText = context.review.address;
1286 if ((context.operationType &
SKIPPABLE_OPERATION) && (context.review.skipDisplay ==
false)
1287 && ((context.currentPage > reviewPages)
1291 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1294 info.
icon = &C_Information_circle_14px;
1295 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1298 context.review.skipDisplay =
true;
1299 context.firstPairPage = reviewPages;
1302 context.review.skipDisplay =
false;
1303 bool isCenteredInfo =
false;
1304 pairIndex = context.currentPage - reviewPages;
1305 if (context.review.address != NULL) {
1308 getPairData(context.review.tagValueList,
1315 if (extension != NULL) {
1316 context.stepCallback = displayAliasFullValue;
1317 context.review.currentTagValueIndex = pairIndex;
1318 forcedType = FORCE_BUTTON;
1321 if (isCenteredInfo) {
1322 forcedType = FORCE_CENTERED_INFO;
1327 drawStep(pos, icon, text, subText, reviewCallback,
false, forcedType,
false);
1334 const char *text = NULL;
1335 const char *subText = NULL;
1337 uint8_t reviewPages = 0;
1338 uint8_t titleIndex = 255;
1339 uint8_t subIndex = 255;
1341 ForcedType_t forcedType = NO_FORCED_TYPE;
1343 context.stepCallback = NULL;
1344 switch (context.type) {
1345 case STREAMING_START_REVIEW_USE_CASE:
1347 titleIndex = reviewPages++;
1348 if (context.review.reviewSubTitle) {
1350 subIndex = reviewPages++;
1353 if (context.currentPage >= reviewPages) {
1358 if (context.currentPage == titleIndex) {
1360 icon = context.review.icon;
1361 text = context.review.reviewTitle;
1363 else if (context.currentPage == subIndex) {
1365 text = context.review.reviewSubTitle;
1369 case STREAMING_CONTINUE_REVIEW_USE_CASE:
1370 if (context.currentPage >= context.review.tagValueList->nbPairs) {
1377 if ((context.review.skipCallback != NULL) && (context.review.skipDisplay ==
false)
1378 && ((context.review.nbDataSets > 1) || (context.currentPage > 0)
1382 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1385 info.
icon = &C_Information_circle_14px;
1386 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1389 context.review.skipDisplay =
true;
1392 context.review.skipDisplay =
false;
1393 bool isCenteredInfo =
false;
1394 getPairData(context.review.tagValueList,
1395 context.currentPage,
1401 if (extension != NULL) {
1402 forcedType = FORCE_BUTTON;
1405 if (isCenteredInfo) {
1406 forcedType = FORCE_CENTERED_INFO;
1411 case STREAMING_FINISH_REVIEW_USE_CASE:
1413 if (context.currentPage == 0) {
1415 getLastPageInfo(
true, &icon, &text);
1419 getLastPageInfo(
false, &icon, &text);
1424 drawStep(pos, icon, text, subText, streamingReviewCallback,
false, forcedType,
false);
1431 const char *text = NULL;
1432 const char *subText = NULL;
1435 context.stepCallback = NULL;
1437 if (context.currentPage < (context.nbPages - 1)) {
1439 ((
const char *
const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
1441 ((
const char *
const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
1444 icon = &C_icon_back_x;
1446 context.stepCallback = startUseCaseHome;
1449 drawStep(pos, icon, text, subText, infoCallback,
false, FORCE_CENTERED_INFO,
false);
1454static void getContentPage(
bool toogle_state, PageContent_t *contentPage)
1456 uint8_t elemIdx = 0;
1461 char **names = NULL;
1463 char **texts = NULL;
1464 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
1465 if (p_content == NULL) {
1467 "getContentPage(): p_content is NULL for page %d\n",
1468 context.currentPage);
1471 switch (p_content->
type) {
1488 &contentPage->subText,
1489 &contentPage->extension,
1491 &contentPage->isCenteredInfo);
1494 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
1498 &contentPage->subText,
1499 &contentPage->extension,
1501 &contentPage->isCenteredInfo);
1505 contentPage->icon = &C_icon_validate_14;
1506 contentPage->isAction =
true;
1510 contentPage->isSwitch =
true;
1513 contentPage->
text = contentSwitch->
text;
1514 contentPage->state = contentSwitch->
initState;
1518 context.stepCallback = onSwitchAction;
1519 contentPage->subText = contentSwitch->
subText;
1524 contentPage->subText
1536 names = (
char **) PIC(contentChoices->
names);
1539 if (contentChoices->
title != NULL) {
1540 contentPage->text = PIC(contentChoices->
title);
1541 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1543 else if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1544 contentPage->text = PIC(context.content.title);
1545 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1547 else if (((context.type == GENERIC_SETTINGS) || (context.type == SETTINGS_USE_CASE))
1548 && (context.home.appName != NULL)) {
1555 contentPage->text = PIC(context.home.appName);
1556 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1559 contentPage->text = (
const char *) PIC(names[elemIdx]);
1566 && (elemIdx == contentChoices->
initChoice)) {
1568 contentPage->bottomIcon =
true;
1576 texts = (
char **) PIC(contentBars->
barTexts);
1579 if (contentBars->
title != NULL) {
1580 contentPage->text = PIC(contentBars->
title);
1581 contentPage->subText = PIC(texts[elemIdx]);
1583 else if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1584 contentPage->text = PIC(context.content.title);
1585 contentPage->subText = PIC(texts[elemIdx]);
1587 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1588 contentPage->text = PIC(context.home.appName);
1589 contentPage->subText = PIC(texts[elemIdx]);
1592 contentPage->text = PIC(texts[elemIdx]);
1600 contentPage->icon = &C_icon_down;
1601 contentPage->bottomIcon =
true;
1611 PageContent_t contentPage = {0};
1613 context.stepCallback = NULL;
1615 if (context.currentPage < (context.nbPages - 1)) {
1616 getContentPage(toogle_state, &contentPage);
1619 contentPage.icon = &C_icon_back_x;
1620 contentPage.text =
"Back";
1621 if (context.type == GENERIC_SETTINGS) {
1622 context.stepCallback = context.home.quitCallback;
1625 context.stepCallback = startUseCaseHome;
1629 if (contentPage.isSwitch) {
1631 pos, contentPage.text, contentPage.subText, contentPage.state, settingsCallback,
false);
1637 contentPage.subText,
1641 contentPage.bottomIcon);
1647static void startUseCaseHome(
void)
1649 switch (context.type) {
1650 case SETTINGS_USE_CASE:
1652 context.currentPage = 1;
1653 if (context.home.homeAction) {
1655 context.currentPage++;
1660 context.currentPage = 1;
1661 if (context.home.homeAction) {
1663 context.currentPage++;
1665 if (context.home.settingContents) {
1667 context.currentPage++;
1672 context.currentPage = 0;
1676 context.type = HOME_USE_CASE;
1677 context.nbPages = 2;
1678 if (context.home.settingContents) {
1681 if (context.home.infosList) {
1684 if (context.home.homeAction) {
1690static void startUseCaseInfo(
void)
1692 context.type = INFO_USE_CASE;
1693 context.nbPages = context.home.infosList->nbInfos + 1;
1694 context.currentPage = 0;
1699static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1705 if (context.type != GENERIC_SETTINGS) {
1706 context.
type = SETTINGS_USE_CASE;
1709 context.nbPages = 1;
1710 for (
unsigned int i = 0; i < context.home.settingContents->nbContents; i++) {
1711 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1712 context.nbPages += getContentNbElement(p_content);
1714 context.currentPage = initSettingPage;
1719static void startUseCaseSettings(
void)
1721 startUseCaseSettingsAtPage(0);
1724static void startUseCaseContent(
void)
1726 uint8_t contentIdx = 0;
1730 context.nbPages = 1;
1732 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1733 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1734 context.nbPages += getContentNbElement(p_content);
1738 if (context.currentPage >= context.nbPages) {
1748 const char *text = NULL;
1749 const char *subText = NULL;
1751 uint8_t currentIndex = 0;
1752 uint8_t homeIndex = 255;
1753 uint8_t actionIndex = 255;
1754 uint8_t settingsIndex = 255;
1755 uint8_t infoIndex = 255;
1757 context.stepCallback = NULL;
1760 homeIndex = currentIndex++;
1761 if (context.home.homeAction) {
1762 actionIndex = currentIndex++;
1764 if (context.home.settingContents) {
1765 settingsIndex = currentIndex++;
1767 if (context.home.infosList) {
1768 infoIndex = currentIndex++;
1771 if (context.currentPage == homeIndex) {
1773 icon = context.home.appIcon;
1774 if (context.home.tagline != NULL) {
1775 text = context.home.tagline;
1778 text = context.home.appName;
1779 subText =
"app is ready";
1782 else if (context.currentPage == actionIndex) {
1784 icon = context.home.homeAction->icon;
1785 text = PIC(context.home.homeAction->text);
1786 context.stepCallback = context.home.homeAction->callback;
1788 else if (context.currentPage == settingsIndex) {
1790 icon = &C_icon_coggle;
1791 text =
"App settings";
1792 context.stepCallback = startUseCaseSettings;
1794 else if (context.currentPage == infoIndex) {
1796 icon = &C_Information_circle_14px;
1798 context.stepCallback = startUseCaseInfo;
1801 icon = &C_Quit_14px;
1803 context.stepCallback = context.home.quitCallback;
1806 drawStep(pos, icon, text, subText, homeCallback,
false, NO_FORCED_TYPE,
false);
1813 const char *text = NULL;
1814 const char *subText = NULL;
1819 uint8_t acceptPage = 0;
1822 uint8_t nbDetailPages = 0;
1824 if (context.choice.message != NULL) {
1825 if ((context.choice.icon == NULL) || (context.choice.subMessage == NULL)) {
1832 if ((context.choice.details != NULL) && (context.choice.details->type ==
BAR_LIST_WARNING)) {
1833 nbDetailPages = context.choice.details->barList.nbBars;
1835 context.stepCallback = NULL;
1837 if (context.currentPage < acceptPage) {
1838 if (context.currentPage == 0) {
1839 text = context.choice.message;
1840 if (context.choice.icon != NULL) {
1841 icon = context.choice.icon;
1844 subText = context.choice.subMessage;
1847 else if ((acceptPage == 2) && (context.currentPage == 1)) {
1849 text = context.choice.message;
1850 subText = context.choice.subMessage;
1853 else if (context.currentPage < (acceptPage + nbDetailPages)) {
1855 uint8_t idx = context.currentPage - acceptPage;
1856 text = (context.choice.details->barList.texts != NULL)
1857 ? context.choice.details->barList.texts[idx]
1859 subText = (context.choice.details->barList.subTexts != NULL)
1860 ? context.choice.details->barList.subTexts[idx]
1863 else if (context.currentPage == (acceptPage + nbDetailPages)) {
1864 icon = &C_icon_validate_14;
1865 text = context.choice.confirmText;
1866 context.stepCallback = onChoiceAccept;
1869 icon = &C_icon_crossmark;
1870 text = context.choice.cancelText;
1871 context.stepCallback = onChoiceReject;
1875 drawStep(pos, icon, text, subText, genericChoiceCallback,
false, NO_FORCED_TYPE,
false);
1882 const char *text = NULL;
1883 const char *subText = NULL;
1886 context.stepCallback = NULL;
1887 switch (context.currentPage) {
1890 text = context.confirm.message;
1891 subText = context.confirm.subMessage;
1895 icon = &C_icon_validate_14;
1896 text = context.confirm.confirmText;
1897 context.stepCallback = onConfirmAccept;
1901 icon = &C_icon_crossmark;
1902 text = context.confirm.cancelText;
1903 context.stepCallback = onConfirmReject;
1907 drawStep(pos, icon, text, subText, genericConfirmCallback,
true, NO_FORCED_TYPE,
false);
1914 PageContent_t contentPage = {0};
1915 ForcedType_t forcedType = NO_FORCED_TYPE;
1917 context.stepCallback = NULL;
1919 if (context.currentPage < (context.nbPages - 1)) {
1920 getContentPage(toogle_state, &contentPage);
1921 if (contentPage.isCenteredInfo) {
1922 forcedType = FORCE_CENTERED_INFO;
1924 context.forceAction = contentPage.isAction;
1927 if (context.content.rejectText) {
1928 contentPage.text = context.content.rejectText;
1931 contentPage.text =
"Back";
1933 if (context.type == GENERIC_REVIEW_USE_CASE) {
1934 contentPage.icon = &C_icon_crossmark;
1937 contentPage.icon = &C_icon_back_x;
1939 context.stepCallback = context.content.quitCallback;
1942 if (contentPage.isSwitch) {
1944 pos, contentPage.text, contentPage.subText, contentPage.state, contentCallback,
false);
1950 contentPage.subText,
1954 contentPage.bottomIcon);
1956 context.forceAction =
false;
1960static void displaySpinner(
const char *text)
1962 drawStep(
SINGLE_STEP, &C_icon_processing, text, NULL, NULL,
false, NO_FORCED_TYPE,
false);
1967static void useCaseReview(ContextType_t type,
1971 const char *reviewTitle,
1972 const char *reviewSubTitle,
1973 const char *finishTitle,
1976 memset(&context, 0,
sizeof(UseCaseContext_t));
1977 context.type = type;
1978 context.operationType = operationType;
1979 context.review.tagValueList = tagValueList;
1980 context.review.reviewTitle = reviewTitle;
1981 context.review.reviewSubTitle = reviewSubTitle;
1982 context.review.finishTitle = finishTitle;
1983 context.review.icon = icon;
1984 context.review.onChoice = choiceCallback;
1985 context.currentPage = 0;
1987 context.nbPages = tagValueList->
nbPairs + 3;
1988 if (reviewSubTitle) {
1996static void setPinCodeText(
void)
1998 bool enableValidate =
false;
1999 bool enableBackspace =
true;
2002 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
2004 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
2006 context.keypad.hidden,
2007 context.keypad.pinLen,
2008 (
const char *) context.keypad.pinEntry);
2010 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
2016static void keypadCallback(
char touchedKey)
2018 switch (touchedKey) {
2020 if (context.keypad.pinLen > 0) {
2021 context.keypad.pinLen--;
2022 context.keypad.pinEntry[context.keypad.pinLen] = 0;
2024 else if (context.keypad.backCallback != NULL) {
2025 context.keypad.backCallback();
2032 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
2036 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
2037 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
2038 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
2039 context.keypad.pinLen++;
2052 const char **buttons;
2053 int firstButtonToken;
2054 uint8_t nbUsedButtons;
2058} savedKeyboardContext;
2073static void displaySuggestionSelection(
void)
2076 savedKeyboardContext.buttons = context.keyboard.content.suggestionButtons.buttons;
2077 savedKeyboardContext.firstButtonToken
2078 = context.keyboard.content.suggestionButtons.firstButtonToken;
2079 savedKeyboardContext.nbUsedButtons = context.keyboard.content.suggestionButtons.nbUsedButtons;
2080 savedKeyboardContext.onButtonCallback = context.keyboard.onButtonCallback;
2081 savedKeyboardContext.backCallback = context.keyboard.backCallback;
2085 context.keyboard.layoutCtx = NULL;
2087 snprintf(savedKeyboardContext.title,
2088 sizeof(savedKeyboardContext.title),
2090 context.keyboard.content.number);
2094 savedKeyboardContext.backCallback,
2095 suggestionNavCallback,
2096 savedKeyboardContext.onButtonCallback);
2100static void keyboardCallback(
char touchedKey)
2103 size_t textLen = strlen(context.keyboard.entryBuffer);
2104 PRINTF(
"[keyboardCallback] touchedKey: '%c'\n", touchedKey);
2108 context.keyboard.backCallback();
2111 context.keyboard.entryBuffer[--textLen] =
'\0';
2114 context.keyboard.actionCallback();
2118 context.keyboard.entryBuffer[textLen] = touchedKey;
2119 context.keyboard.entryBuffer[++textLen] =
'\0';
2124 context.keyboard.getSuggestButtons(&context.keyboard.content, &mask);
2126 = &context.keyboard.content.suggestionButtons;
2133 bool allCandidatesFit;
2141 displaySuggestionSelection();
2145 else if (textLen >= context.keyboard.entryMaxLen) {
2151 context.keyboard.layoutCtx, context.keyboard.textIndex, context.keyboard.entryBuffer);
2157static void launchReviewAfterWarning(
void)
2159 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
2160 useCaseReview(reviewWithWarnCtx.type,
2161 reviewWithWarnCtx.operationType,
2162 reviewWithWarnCtx.tagValueList,
2163 reviewWithWarnCtx.icon,
2164 reviewWithWarnCtx.reviewTitle,
2165 reviewWithWarnCtx.reviewSubTitle,
2166 reviewWithWarnCtx.finishTitle,
2167 reviewWithWarnCtx.choiceCallback);
2169 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
2179 displayWarningStep();
2184static void displayBarDetailStep(
void)
2187 = &reviewWithWarnCtx.warning->introDetails->
barList.
details[reviewWithWarnCtx.barDetailIdx];
2210 if (reviewWithWarnCtx.warningPage > 0) {
2211 reviewWithWarnCtx.warningPage--;
2216 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
2217 reviewWithWarnCtx.warningPage++;
2219 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2220 && (reviewWithWarnCtx.warning->info != NULL)) {
2221 launchReviewAfterWarning();
2228 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2229 launchReviewAfterWarning();
2232 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2233 reviewWithWarnCtx.choiceCallback(
false);
2237 else if ((event ==
BUTTON_BOTH_PRESSED) && (reviewWithWarnCtx.warning->introDetails != NULL)
2239 && (reviewWithWarnCtx.warningPage > reviewWithWarnCtx.firstWarningPage)) {
2241 barIdx = reviewWithWarnCtx.warningPage - reviewWithWarnCtx.firstWarningPage - 1;
2242 if ((reviewWithWarnCtx.warning->introDetails->barList.details != NULL)
2243 && (reviewWithWarnCtx.warning->introDetails->barList.details[barIdx].type
2245 reviewWithWarnCtx.barDetailIdx = barIdx;
2246 displayBarDetailStep();
2253 displayWarningStep();
2257static void displayWarningStep(
void)
2262 if ((reviewWithWarnCtx.warning->prelude) && (reviewWithWarnCtx.warningPage == 0)) {
2267 reviewWithWarnCtx.warning->prelude->title,
2268 reviewWithWarnCtx.warning->prelude->description,
2275 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2277 info.
icon = &C_icon_warning;
2278 info.
text1 =
"Blind signing ahead";
2279 info.
text2 =
"To accept risk, press both buttons";
2280 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2284 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2285 getLastPageInfo(
false, &info.
icon, &info.
text1);
2289 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2290 && (reviewWithWarnCtx.warning->info != NULL)) {
2291 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2292 info.
icon = reviewWithWarnCtx.warning->info->icon;
2293 info.
text1 = reviewWithWarnCtx.warning->info->title;
2294 info.
text2 = reviewWithWarnCtx.warning->info->description;
2295 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2299 else if ((reviewWithWarnCtx.warning->introDetails != NULL)
2302 barIdx = reviewWithWarnCtx.warningPage - reviewWithWarnCtx.firstWarningPage - 1;
2303 if (reviewWithWarnCtx.warning->introDetails->barList.icons) {
2304 info.
icon = reviewWithWarnCtx.warning->introDetails->barList.icons[barIdx];
2306 info.
text1 = reviewWithWarnCtx.warning->introDetails->barList.texts[barIdx];
2307 if (reviewWithWarnCtx.warning->introDetails->barList.subTexts) {
2308 info.
text2 = reviewWithWarnCtx.warning->introDetails->barList.subTexts[barIdx];
2312 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2313 if ((reviewWithWarnCtx.warning->introDetails != NULL)
2315 info.
icon = reviewWithWarnCtx.warning->introDetails->centeredInfo.icon;
2316 info.
text1 = reviewWithWarnCtx.warning->introDetails->centeredInfo.title;
2317 info.
text2 = reviewWithWarnCtx.warning->introDetails->centeredInfo.description;
2336static void displayInitialWarning(
void)
2339 reviewWithWarnCtx.warningPage = 0;
2341 || ((reviewWithWarnCtx.warning->introDetails)
2343 reviewWithWarnCtx.nbWarningPages = 2;
2345 else if ((reviewWithWarnCtx.warning->introDetails)
2347 reviewWithWarnCtx.nbWarningPages
2348 = reviewWithWarnCtx.warning->introDetails->barList.nbBars + 1;
2352 reviewWithWarnCtx.nbWarningPages = 1;
2355 reviewWithWarnCtx.firstWarningPage = 0;
2356 displayWarningStep();
2360static void displayPrelude(
void)
2363 reviewWithWarnCtx.warningPage = 0;
2365 || ((reviewWithWarnCtx.warning->introDetails)
2367 reviewWithWarnCtx.nbWarningPages = 3;
2371 reviewWithWarnCtx.nbWarningPages = 2;
2373 reviewWithWarnCtx.firstWarningPage = 1;
2374 displayWarningStep();
2395 bool *requireSpecificDisplay)
2398 UNUSED(tagValueList);
2400 *requireSpecificDisplay =
true;
2420 bool *requireSpecificDisplay)
2423 UNUSED(tagValueList);
2425 UNUSED(isSkippable);
2426 *requireSpecificDisplay =
true;
2464 UNUSED(switchesList);
2504 UNUSED(choicesList);
2518 uint8_t nbPages = 0;
2519 uint8_t nbPairs = tagValueList->
nbPairs;
2520 uint8_t nbPairsInPage;
2524 while (i < tagValueList->nbPairs) {
2528 nbPairs -= nbPairsInPage;
2554 memset(&context, 0,
sizeof(UseCaseContext_t));
2555 context.type = CONTENT_USE_CASE;
2556 context.currentPage = initPage;
2557 context.content.title = title;
2558 context.content.quitCallback = quitCallback;
2559 context.content.navCallback = navCallback;
2560 context.content.controlsCallback = controlsCallback;
2561 context.content.genericContents.callbackCallNeeded =
true;
2562 context.content.genericContents.nbContents = nbPages;
2564 startUseCaseContent();
2583 const char *tagline,
2584 const uint8_t initSettingPage,
2590 memset(&context, 0,
sizeof(UseCaseContext_t));
2591 context.home.appName = appName;
2592 context.home.appIcon = appIcon;
2593 context.home.tagline = tagline;
2594 context.home.settingContents = PIC(settingContents);
2595 context.home.infosList = PIC(infosList);
2596 context.home.homeAction = action;
2597 context.home.quitCallback = quitCallback;
2599 if ((initSettingPage !=
INIT_HOME_PAGE) && (settingContents != NULL)) {
2600 startUseCaseSettingsAtPage(initSettingPage);
2625 memset(&context, 0,
sizeof(UseCaseContext_t));
2626 context.type = GENERIC_SETTINGS;
2627 context.home.appName = appName;
2628 context.home.settingContents = PIC(settingContents);
2629 context.home.infosList = PIC(infosList);
2630 context.home.quitCallback = quitCallback;
2632 startUseCaseSettingsAtPage(initPage);
2671 const char *reviewTitle,
2672 const char *reviewSubTitle,
2673 const char *finishTitle,
2676 useCaseReview(REVIEW_USE_CASE,
2711 const char *reviewTitle,
2712 const char *reviewSubTitle,
2713 const char *finishTitle,
2719 ContextType_t type = REVIEW_USE_CASE;
2722 if ((warning == NULL)
2742 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
2743 reviewWithWarnCtx.type = type;
2744 reviewWithWarnCtx.operationType = operationType;
2745 reviewWithWarnCtx.tagValueList = tagValueList;
2746 reviewWithWarnCtx.icon = icon;
2747 reviewWithWarnCtx.reviewTitle = reviewTitle;
2748 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2749 reviewWithWarnCtx.finishTitle = finishTitle;
2750 reviewWithWarnCtx.warning = warning;
2751 reviewWithWarnCtx.choiceCallback = choiceCallback;
2754 if (reviewWithWarnCtx.warning->prelude) {
2759 displayInitialWarning();
2795 const char *reviewTitle,
2796 const char *reviewSubTitle,
2797 const char *finishTitle,
2808 &blindSigningWarning,
2829 const char *reviewTitle,
2830 const char *reviewSubTitle,
2831 const char *finishTitle,
2862 const char *reviewTitle,
2863 const char *reviewSubTitle,
2866 memset(&context, 0,
sizeof(UseCaseContext_t));
2867 context.type = ADDRESS_REVIEW_USE_CASE;
2868 context.review.address = address;
2869 context.review.reviewTitle = reviewTitle;
2870 context.review.reviewSubTitle = reviewSubTitle;
2871 context.review.icon = icon;
2872 context.review.onChoice = choiceCallback;
2873 context.currentPage = 0;
2876 context.nbPages = reviewSubTitle ? 5 : 4;
2877 if (additionalTagValueList) {
2878 context.review.tagValueList = PIC(additionalTagValueList);
2879 context.nbPages += additionalTagValueList->
nbPairs;
2894 const char *rejectText,
2897 memset(&context, 0,
sizeof(UseCaseContext_t));
2898 context.type = GENERIC_REVIEW_USE_CASE;
2899 context.content.rejectText = rejectText;
2900 context.content.quitCallback = rejectCallback;
2901 context.content.genericContents.nbContents = contents->
nbContents;
2907 context.content.genericContents.contentsList = PIC(contents->
contentsList);
2910 startUseCaseContent();
2924 memset(&context, 0,
sizeof(UseCaseContext_t));
2925 context.type = STATUS_USE_CASE;
2926 context.stepCallback = quitCallback;
2927 context.currentPage = 0;
2928 context.nbPages = 1;
2934 statusButtonCallback,
2951 switch (reviewStatusType) {
2953 msg =
"Operation signed";
2957 msg =
"Operation rejected";
2961 msg =
"Transaction signed";
2965 msg =
"Transaction rejected";
2969 msg =
"Message signed";
2973 msg =
"Message rejected";
2977 msg =
"Address verified";
2981 msg =
"Address verification cancelled";
3004 const char *reviewTitle,
3005 const char *reviewSubTitle,
3009 streamingOpType = operationType;
3011 memset(&context, 0,
sizeof(UseCaseContext_t));
3012 context.type = STREAMING_START_REVIEW_USE_CASE;
3013 context.operationType = operationType;
3014 context.review.reviewTitle = reviewTitle;
3015 context.review.reviewSubTitle = reviewSubTitle;
3016 context.review.icon = icon;
3017 context.review.onChoice = choiceCallback;
3018 context.currentPage = 0;
3019 context.nbPages = reviewSubTitle ? 3 : 2;
3039 const char *reviewTitle,
3040 const char *reviewSubTitle,
3044 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
3064 const char *reviewTitle,
3065 const char *reviewSubTitle,
3069 memset(&context, 0,
sizeof(UseCaseContext_t));
3070 context.type = STREAMING_START_REVIEW_USE_CASE;
3071 context.operationType = operationType;
3072 context.review.reviewTitle = reviewTitle;
3073 context.review.reviewSubTitle = reviewSubTitle;
3074 context.review.icon = icon;
3075 context.review.onChoice = choiceCallback;
3076 context.currentPage = 0;
3077 context.nbPages = reviewSubTitle ? 3 : 2;
3080 streamingOpType = operationType;
3083 if ((warning == NULL)
3095 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
3097 reviewWithWarnCtx.type = context.type;
3098 reviewWithWarnCtx.operationType = operationType;
3099 reviewWithWarnCtx.icon = icon;
3100 reviewWithWarnCtx.reviewTitle = reviewTitle;
3101 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
3102 reviewWithWarnCtx.choiceCallback = choiceCallback;
3103 reviewWithWarnCtx.warning = warning;
3106 if (reviewWithWarnCtx.warning->prelude) {
3111 displayInitialWarning();
3135 uint8_t curNbDataSets = context.review.nbDataSets;
3137 memset(&context, 0,
sizeof(UseCaseContext_t));
3138 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
3139 context.operationType = streamingOpType;
3140 context.review.tagValueList = tagValueList;
3141 context.review.onChoice = choiceCallback;
3142 context.currentPage = 0;
3143 context.nbPages = tagValueList->
nbPairs + 1;
3144 context.review.skipCallback = skipCallback;
3145 context.review.nbDataSets = curNbDataSets + 1;
3169 memset(&context, 0,
sizeof(UseCaseContext_t));
3170 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
3171 context.operationType = streamingOpType;
3172 context.review.onChoice = choiceCallback;
3173 context.review.finishTitle = finishTitle;
3174 context.currentPage = 0;
3175 context.nbPages = 2;
3187 memset(&context, 0,
sizeof(UseCaseContext_t));
3188 context.type = SPINNER_USE_CASE;
3189 context.currentPage = 0;
3190 context.nbPages = 1;
3192 displaySpinner(text);
3208 const char *message,
3209 const char *subMessage,
3210 const char *confirmText,
3211 const char *cancelText,
3215 icon, message, subMessage, confirmText, cancelText, NULL, callback);
3233 const char *message,
3234 const char *subMessage,
3235 const char *confirmText,
3236 const char *cancelText,
3240 memset(&context, 0,
sizeof(UseCaseContext_t));
3241 context.type = CHOICE_USE_CASE;
3242 context.choice.icon = icon;
3243 context.choice.message = message;
3244 context.choice.subMessage = subMessage;
3245 context.choice.confirmText = confirmText;
3246 context.choice.cancelText = cancelText;
3247 context.choice.onChoice = callback;
3248 context.choice.details = details;
3249 context.currentPage = 0;
3250 context.nbPages = 2;
3251 if (message != NULL) {
3254 if ((icon != NULL) && (subMessage != NULL)) {
3258 if (details != NULL) {
3275 const char *message,
3276 const char *subMessage,
3277 const char *confirmText,
3278 const char *cancelText,
3285 centerIcon, title, message, confirmText, cancelText, details, callback);
3302 const char *subMessage,
3303 const char *confirmText,
3304 const char *cancelText,
3307 memset(&context, 0,
sizeof(UseCaseContext_t));
3308 context.type = CONFIRM_USE_CASE;
3309 context.confirm.message = message;
3310 context.confirm.subMessage = subMessage;
3311 context.confirm.confirmText = confirmText;
3312 context.confirm.cancelText = cancelText;
3313 context.confirm.onConfirm = callback;
3314 context.currentPage = 0;
3315 context.nbPages = 1 + 2;
3330 const char *message,
3331 const char *actionText,
3339 memset(&context, 0,
sizeof(UseCaseContext_t));
3340 context.type = ACTION_USE_CASE;
3341 context.action.actionCallback = callback;
3343 centeredInfo.
icon = icon;
3344 centeredInfo.
text1 = message;
3380 memset(&context, 0,
sizeof(KeypadContext_t));
3381 context.type = KEYPAD_USE_CASE;
3382 context.currentPage = 0;
3383 context.nbPages = 1;
3384 context.keypad.validatePin = validatePinCallback;
3385 context.keypad.backCallback = backCallback;
3386 context.keypad.pinMinDigits = minDigits;
3387 context.keypad.pinMaxDigits = maxDigits;
3388 context.keypad.hidden = hidden;
3395 USE_CASE_LOGGER,
"nbgl_useCaseKeypad(): layout setup failed (status=%d)\n", status);
3398 context.keypad.keypadIndex = status;
3403 USE_CASE_LOGGER,
"nbgl_useCaseKeypad(): layout setup failed (status=%d)\n", status);
3408 if (context.keypad.backCallback != NULL) {
3449 .mode = params->
mode,
3455 memset(&context, 0,
sizeof(UseCaseContext_t));
3456 context.type = KEYBOARD_USE_CASE;
3457 context.currentPage = 0;
3458 context.nbPages = 1;
3459 context.keyboard.entryBuffer = PIC(params->
entryBuffer);
3460 context.keyboard.entryMaxLen = params->
entryMaxLen;
3461 context.keyboard.entryBuffer[0] =
'\0';
3463 context.keyboard.content.type = params->
type;
3466 context.keyboard.backCallback = PIC(backCallback);
3468 switch (params->
type) {
3475 context.keyboard.getSuggestButtons
3497 USE_CASE_LOGGER,
"nbgl_useCaseKeyboard(): layout setup failed (status=%d)\n", status);
3500 context.keyboard.keyboardIndex = status;
3506 USE_CASE_LOGGER,
"nbgl_useCaseKeyboard(): layout setup failed (status=%d)\n", status);
3509 context.keyboard.textIndex = status;
nbgl_contentCenteredInfoStyle_t
possible styles for Centered Info Area
@ BOLD_TEXT1_INFO
bold is used for text1 (but '\b' can switch to regular)
@ BUTTON_INFO
bold is used for text1 and text2 as a white button
@ REGULAR_INFO
both texts regular (but '\b' can switch to bold)
@ CHOICES_LIST
list of choices through radio buttons
@ CENTERED_INFO
a centered info
@ SWITCHES_LIST
list of switches with descriptions
@ 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
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)
static void drawStep(FlowContext_t *ctx, nbgl_stepPosition_t pos, bool modal, const nbgl_icon_details_t *icon, const char *txt, const char *subTxt)
void(* nbgl_stepCallback_t)(void)
prototype of function to be called when a step is using a callback on "double-key" action
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
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.
@ HORIZONTAL_NAV
'<' and '>' are displayed, to navigate between pages and steps
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_layoutUpdateEnteredText(nbgl_layout_t *layout, uint8_t index, const char *text)
Updates an existing "text entry" area, created with nbgl_layoutAddEnteredText()
@ LEFT_ARROW
left arrow is used
@ RIGHT_ARROW
right arrow is used
int nbgl_layoutAddNavigation(nbgl_layout_t *layout, nbgl_layoutNavigation_t *info)
Creates navigation arrows on side(s) of the screen.
int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, const char *text, bool lettersOnly)
Adds a "text entry" area under the previously entered object. The max number of really displayable ch...
int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredInfo_t *info)
Creates an area on the center of the main panel, with a possible icon/image, a possible text in black...
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
#define NB_MAX_SUGGESTION_BUTTONS
void * nbgl_layout_t
type shared externally
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_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()
#define KEYBOARD_MAX_TITLE
@ BUTTON_BOTH_PRESSED
Sent when both buttons are released.
@ BUTTON_LEFT_PRESSED
Sent when Left button is released.
@ BUTTON_RIGHT_PRESSED
Send when Right button is released.
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screenRedraw(void)
void(* nbgl_stepButtonCallback_t)(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
prototype of function to be called when buttons are touched on a screen
#define GET_POS_OF_STEP(_step, _nb_steps)
nbgl_step_t nbgl_stepDrawSwitch(nbgl_stepPosition_t pos, nbgl_stepButtonCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, nbgl_layoutSwitch_t *switchInfo, bool modal)
draw a step page with a switch and navigation arrows to navigate to other pages.
void * nbgl_step_t
type shared externally
uint8_t nbgl_stepPosition_t
this type is a bitfield containing:
nbgl_step_t nbgl_stepDrawMenuList(nbgl_stepMenuListCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, nbgl_layoutMenuList_t *list, bool modal)
draw a step page with a menu list and navigation arrows to parse it. This step must be alone
#define ACTION_ON_ANY_BUTTON
When action callback applies only on both button press.
int nbgl_stepRelease(nbgl_step_t step)
Release the step obtained with any of the nbgl_stepDrawXXX() functions.
#define FORWARD_DIRECTION
When the flow is navigated from last to first step.
@ NEITHER_FIRST_NOR_LAST_STEP
neither first nor last in a multiple steps flow
@ SINGLE_STEP
single step flow
@ LAST_STEP
last in a multiple steps flow
@ FIRST_STEP
first in a multiple steps flow
nbgl_step_t nbgl_stepDrawText(nbgl_stepPosition_t pos, nbgl_stepButtonCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, const char *text, const char *subText, nbgl_contentCenteredInfoStyle_t style, bool modal)
draws a text type step, that can be multi-pages, depending of the length of text and subText....
nbgl_step_t nbgl_stepDrawCenteredInfo(nbgl_stepPosition_t pos, nbgl_stepButtonCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, nbgl_layoutCenteredInfo_t *info, bool modal)
draw a step with a centered info (icon + text). This is always a single page step
#define BACKWARD_DIRECTION
When action callback applies on any button press.
nbgl_state_t
to represent a boolean state.
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
API of the Advanced BOLOS Graphical Library, for typical application use-cases.
@ 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)
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)
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
@ BLIND_SIGNING_WARN
Blind signing.
@ W3C_NO_THREAT_WARN
Web3 Checks: No Threat detected.
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)
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 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 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.
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)
const char * title
Nano only and used in the horizontal flow: per-content header text. Same semantics as nbgl_contentRad...
uint8_t nbBars
number of elements in barTexts and tokens array
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)
This structure contains info to build a centered (vertically and horizontally) area,...
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
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
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)
uint8_t nbInfos
number of elements in infoTypes and infoContents array
This structure contains a list of names to build a list of radio buttons (on the right part of screen...
uint8_t token
the token that will be used as argument of the callback
uint8_t initChoice
index of the current choice
const char *const * names
array of strings giving the choices (nbChoices)
const nbgl_icon_details_t * selectionIcon
uint8_t nbChoices
number of choices
const char * title
Nano only and used in the horizontal flow (i.e. vertical is false): per-content header text shown abo...
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
uint8_t token
the token that will be used as argument of the callback (unused on Nano)
nbgl_state_t initState
initial state of the switch
const char * subText
description under main text (NULL terminated, single line, may be null)
const char * confirmationText
text of the confirmation button, if NULL "It matches" is used
uint8_t confirmationToken
the token used as argument of the onActionCallback
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
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 ...
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
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...
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.
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
Structure containing all information when creating a layout. This structure must be passed as argumen...
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 to build a navigation bar at the bottom of the screen.
nbgl_layoutNavDirection_t direction
vertical or horizontal navigation
This structure contains data to build a page in multi-pages mode (nbgl_pageDrawGenericContent)
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
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
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
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...
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 * reviewDetails
const nbgl_contentCenter_t * info
parameters to build the intro warning page, if not using pre-defined
nbgl_contentInfoList_t infosList
INFOS_LIST 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_contentSwitchesList_t switchesList
SWITCHES_LIST type
nbgl_contentInfoButton_t infoButton
INFO_BUTTON type
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type