18#include "os_helpers.h"
24#define WITH_HORIZONTAL_CHOICES_LIST
25#define WITH_HORIZONTAL_BARS_LIST
32#define RISKY_OPERATION (1 << 6)
39#define NO_THREAT_OPERATION (1 << 7)
45typedef struct ReviewContext_s {
49 const char *reviewTitle;
50 const char *reviewSubTitle;
51 const char *finishTitle;
56 uint8_t dataDirection;
57 uint8_t currentTagValueIndex;
58 uint8_t currentExtensionPage;
59 uint8_t nbExtensionPages;
65typedef struct ChoiceContext_s {
68 const char *subMessage;
69 const char *confirmText;
70 const char *cancelText;
75typedef struct ConfirmContext_s {
77 const char *subMessage;
78 const char *confirmText;
79 const char *cancelText;
84typedef struct ContentContext_s {
87 const char *rejectText;
93typedef struct HomeContext_s {
103typedef struct ActionContext_s {
108typedef struct KeypadContext_s {
111 uint8_t pinMinDigits;
112 uint8_t pinMaxDigits;
122typedef struct KeyboardContext_s {
125 uint16_t entryMaxLen;
127 uint8_t keyboardIndex;
140 GENERIC_REVIEW_USE_CASE,
141 ADDRESS_REVIEW_USE_CASE,
142 STREAMING_START_REVIEW_USE_CASE,
143 STREAMING_CONTINUE_REVIEW_USE_CASE,
144 STREAMING_FINISH_REVIEW_USE_CASE,
158typedef struct UseCaseContext_s {
163 uint8_t firstPairPage;
168 ReviewContext_t review;
169 ChoiceContext_t choice;
170 ConfirmContext_t confirm;
172 ContentContext_t content;
174 KeypadContext_t keypad;
177 KeyboardContext_t keyboard;
179 ActionContext_t action;
183typedef struct PageContent_s {
194typedef struct ReviewWithWarningContext_s {
199 const char *reviewTitle;
200 const char *reviewSubTitle;
201 const char *finishTitle;
204 uint8_t securityReportLevel;
207 uint8_t nbWarningPages;
208 uint8_t firstWarningPage;
209} ReviewWithWarningContext_t;
220static UseCaseContext_t context;
222static ReviewWithWarningContext_t reviewWithWarnCtx;
240static void displaySpinner(
const char *text);
242static void startUseCaseHome(
void);
243static void startUseCaseInfo(
void);
244static void startUseCaseSettings(
void);
245static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
246static void startUseCaseContent(
void);
248static void statusTickerCallback(
void);
251static void displayWarningStep(
void);
256 switch (content->
type) {
286 if (contentIdx >= genericContents->
nbContents) {
292 if (content == NULL) {
298 if (context.content.navCallback) {
299 if (context.content.navCallback(contentIdx, &pageContent) ==
true) {
302 switch (content->
type) {
351 uint8_t *elemContentIdx,
357 uint8_t elemNbPages = 0;
359 switch (context.type) {
360 case SETTINGS_USE_CASE:
362 case GENERIC_SETTINGS:
363 genericContents = context.home.settingContents;
365 case CONTENT_USE_CASE:
366 case GENERIC_REVIEW_USE_CASE:
367 genericContents = &context.content.genericContents;
372 for (uint i = 0; i < genericContents->
nbContents; i++) {
373 p_content = getContentAtIdx(genericContents, i, content);
374 elemNbPages = getContentNbElement(p_content);
375 if (nbPages + elemNbPages > elemIdx) {
376 *elemContentIdx = context.currentPage - nbPages;
379 nbPages += elemNbPages;
385static const char *getChoiceName(uint8_t choiceIndex)
395 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
396 if (p_content == NULL) {
399 switch (p_content->
type) {
402 names = (
char **) PIC(contentChoices->
names);
407 names = (
char **) PIC(contentBars->
barTexts);
408 nbValues = contentBars->
nbBars;
414 if (choiceIndex >= nbValues) {
418 return (
const char *) PIC(names[choiceIndex]);
421static void onChoiceSelected(uint8_t choiceIndex)
430 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
431 if (p_content == NULL) {
434 switch (p_content->
type) {
437 if (choiceIndex < contentChoices->nbChoices) {
438 token = contentChoices->
token;
443 if (choiceIndex < contentBars->nbBars) {
444 token = contentBars->
tokens[choiceIndex];
451 if ((token != 255) && (context.content.controlsCallback != NULL)) {
452 context.content.controlsCallback(token, 0);
454 else if (context.content.quitCallback != NULL) {
455 context.content.quitCallback();
465 bool *isCenteredInfo)
469 if (tagValueList->
pairs != NULL) {
470 pair = PIC(&tagValueList->
pairs[index]);
473 pair = PIC(tagValueList->
callback(index));
476 *value = pair->
value;
481 *isCenteredInfo =
true;
489static void onReviewAccept(
void)
491 if (context.review.onChoice) {
492 context.review.onChoice(
true);
496static void onReviewReject(
void)
498 if (context.review.onChoice) {
499 context.review.onChoice(
false);
503static void onChoiceAccept(
void)
505 if (context.choice.onChoice) {
506 context.choice.onChoice(
true);
510static void onChoiceReject(
void)
512 if (context.choice.onChoice) {
513 context.choice.onChoice(
false);
517static void onConfirmAccept(
void)
519 if (context.confirm.currentStep) {
522 if (context.confirm.onConfirm) {
523 context.confirm.onConfirm();
527static void onConfirmReject(
void)
529 if (context.confirm.currentStep) {
536static void onSwitchAction(
void)
543 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
549 switch (context.type) {
550 case SETTINGS_USE_CASE:
552 case GENERIC_SETTINGS:
555 case CONTENT_USE_CASE:
556 case GENERIC_REVIEW_USE_CASE:
564 actionCallback(contentSwitch->
token,
566 context.currentPage);
568 else if (context.content.controlsCallback != NULL) {
569 context.content.controlsCallback(contentSwitch->
token, 0);
579 ForcedType_t forcedType)
590 .tickerIntervale = 0,
596 if ((context.type == STREAMING_CONTINUE_REVIEW_USE_CASE)
597 && (context.review.skipCallback != NULL) && (context.review.nbDataSets > 1)) {
600 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
603 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
608 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
610 switch (p_content->
type) {
632 else if ((icon == NULL) && (forcedType != FORCE_CENTERED_INFO)) {
634 if (subTxt != NULL) {
635 style = (forcedType == FORCE_BUTTON) ? BUTTON_INFO : BOLD_TEXT1_INFO;
638 style = REGULAR_INFO;
640 newStep =
nbgl_stepDrawText(pos, onActionCallback, p_ticker, txt, subTxt, style, modal);
648 if ((subTxt != NULL) || (context.stepCallback != NULL) || context.forceAction) {
649 info.
style = BOLD_TEXT1_INFO;
652 info.
style = REGULAR_INFO;
656 if (context.type == CONFIRM_USE_CASE) {
657 context.confirm.currentStep = newStep;
663 const char *description,
672 switchInfo.
text = title;
673 switchInfo.
subText = description;
686 if (context.currentPage > 0) {
687 context.currentPage--;
691 else if ((context.type != STREAMING_CONTINUE_REVIEW_USE_CASE)
692 || (context.review.skipCallback == NULL) || (context.review.nbDataSets == 1)) {
699 if (context.currentPage < (
int) (context.nbPages - 1)) {
700 context.currentPage++;
710 if (context.stepCallback != NULL) {
711 context.stepCallback();
713 else if ((context.type == CONTENT_USE_CASE) || (context.type == SETTINGS_USE_CASE)
714 || (context.type == GENERIC_SETTINGS)
715 || (context.type == GENERIC_REVIEW_USE_CASE)) {
716 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
717 if (p_content != NULL) {
718 switch (p_content->
type) {
733 index = context.currentPage;
738 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
750 else if (context.content.controlsCallback != NULL) {
751 context.content.controlsCallback(token, index);
766 if (!buttonGenericCallback(event, &pos)) {
771 context.review.dataDirection = pos;
773 displayReviewPage(pos);
785 && (context.currentPage > context.firstPairPage)) {
786 context.currentPage--;
793 && (context.currentPage < (
int) (context.nbPages - 1))
794 && (context.currentPage > context.firstPairPage)) {
795 context.currentPage++;
801 if (context.firstPairPage == 0) {
803 context.review.skipCallback();
807 context.currentPage = context.nbPages - 2;
816 if (context.firstPairPage == 0) {
817 displayStreamingReviewPage(pos);
820 displayReviewPage(pos);
830 context.action.actionCallback();
839 if (!buttonGenericCallback(event, &pos)) {
844 context.review.dataDirection = pos;
847 displayStreamingReviewPage(pos);
855 if (!buttonGenericCallback(event, &pos)) {
859 displaySettingsPage(pos,
false);
867 if (!buttonGenericCallback(event, &pos)) {
871 displayInfoPage(pos);
879 if (!buttonGenericCallback(event, &pos)) {
883 displayHomePage(pos);
891 if (!buttonGenericCallback(event, &pos)) {
895 displayChoicePage(pos);
903 if (!buttonGenericCallback(event, &pos)) {
916 if (context.stepCallback != NULL) {
917 context.stepCallback();
927 if (!buttonGenericCallback(event, &pos)) {
931 displayContent(pos,
false);
935static void statusTickerCallback(
void)
937 if (context.stepCallback != NULL) {
938 context.stepCallback();
950 if (context.review.currentExtensionPage > 0) {
951 context.review.currentExtensionPage--;
957 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
958 context.review.currentExtensionPage++;
964 if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
974 displayExtensionStep(pos);
983 const char *text = NULL;
984 const char *subText = NULL;
986 if (context.review.extensionStepCtx != NULL) {
989 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
990 if (context.review.currentExtensionPage == 0) {
997 switch (context.review.extension->aliasType) {
999 text = context.review.extension->title;
1000 subText = context.review.extension->fullValue;
1003 infoList = context.review.extension->infolist;
1004 text = PIC(infoList->
infoTypes[context.review.currentExtensionPage]);
1005 subText = PIC(infoList->
infoContents[context.review.currentExtensionPage]);
1008 tagValueList = context.review.extension->tagValuelist;
1009 text = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
item);
1010 subText = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
value);
1017 pos, extensionNavigate, NULL, text, subText, BOLD_TEXT1_INFO,
true);
1020 else if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
1022 info.
icon = &C_icon_back_x;
1023 info.
text1 =
"Back";
1024 info.
style = BOLD_TEXT1_INFO;
1026 context.review.extensionStepCtx
1032static void displayAliasFullValue(
void)
1034 const char *text = NULL;
1035 const char *subText = NULL;
1037 bool isCenteredInfo;
1039 getPairData(context.review.tagValueList,
1040 context.review.currentTagValueIndex,
1043 &context.review.extension,
1046 if (context.review.extension == NULL) {
1049 "displayAliasFullValue: extension nor found for pair %d\n",
1050 context.review.currentTagValueIndex);
1053 context.review.currentExtensionPage = 0;
1054 context.review.extensionStepCtx = NULL;
1056 switch (context.review.extension->aliasType) {
1058 context.review.nbExtensionPages = 2;
1061 context.review.nbExtensionPages = context.review.extension->infolist->nbInfos + 1;
1064 context.review.nbExtensionPages = context.review.extension->tagValuelist->nbPairs + 1;
1068 "displayAliasFullValue: unsupported alias type %d\n",
1069 context.review.extension->aliasType);
1075static void getLastPageInfo(
bool approve,
const nbgl_icon_details_t **icon,
const char **text)
1079 *icon = &C_icon_validate_14;
1080 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1085 if (context.review.finishTitle != NULL) {
1086 *text = context.review.finishTitle;
1091 if (context.operationType & RISKY_OPERATION) {
1092 *text =
"Accept risk and sign transaction";
1095 *text =
"Sign transaction";
1099 if (context.operationType & RISKY_OPERATION) {
1100 *text =
"Accept risk and sign message";
1103 *text =
"Sign message";
1107 if (context.operationType & RISKY_OPERATION) {
1108 *text =
"Accept risk and sign operation";
1111 *text =
"Sign operation";
1117 context.stepCallback = onReviewAccept;
1121 *icon = &C_icon_crossmark;
1122 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1126 *text =
"Reject transaction";
1129 *text =
"Reject message";
1132 *text =
"Reject operation";
1134 context.stepCallback = onReviewReject;
1141 uint8_t reviewPages = 0;
1142 uint8_t finalPages = 0;
1143 uint8_t pairIndex = 0;
1144 const char *text = NULL;
1145 const char *subText = NULL;
1147 uint8_t currentIndex = 0;
1148 uint8_t titleIndex = 255;
1149 uint8_t subIndex = 255;
1150 uint8_t approveIndex = 255;
1151 uint8_t rejectIndex = 255;
1153 ForcedType_t forcedType = NO_FORCED_TYPE;
1155 context.stepCallback = NULL;
1159 titleIndex = currentIndex++;
1161 if (context.review.reviewSubTitle) {
1163 subIndex = currentIndex++;
1166 approveIndex = context.nbPages - 2;
1167 rejectIndex = context.nbPages - 1;
1168 finalPages = approveIndex;
1171 if (context.currentPage >= finalPages) {
1172 if (context.currentPage == approveIndex) {
1174 getLastPageInfo(
true, &icon, &text);
1176 else if (context.currentPage == rejectIndex) {
1178 getLastPageInfo(
false, &icon, &text);
1181 else if (context.currentPage < reviewPages) {
1182 if (context.currentPage == titleIndex) {
1184 icon = context.review.icon;
1185 text = context.review.reviewTitle;
1187 else if (context.currentPage == subIndex) {
1189 text = context.review.reviewSubTitle;
1192 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
1195 subText = context.review.address;
1201 if ((context.operationType &
SKIPPABLE_OPERATION) && (context.review.skipDisplay ==
false)
1202 && ((context.currentPage > reviewPages)
1206 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1209 info.
icon = &C_Information_circle_14px;
1210 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1213 context.review.skipDisplay =
true;
1214 context.firstPairPage = reviewPages;
1217 context.review.skipDisplay =
false;
1218 bool isCenteredInfo =
false;
1219 pairIndex = context.currentPage - reviewPages;
1220 if (context.review.address != NULL) {
1223 getPairData(context.review.tagValueList,
1230 if (extension != NULL) {
1231 context.stepCallback = displayAliasFullValue;
1232 context.review.currentTagValueIndex = pairIndex;
1233 forcedType = FORCE_BUTTON;
1236 if (isCenteredInfo) {
1237 forcedType = FORCE_CENTERED_INFO;
1242 drawStep(pos, icon, text, subText, reviewCallback,
false, forcedType);
1249 const char *text = NULL;
1250 const char *subText = NULL;
1252 uint8_t reviewPages = 0;
1253 uint8_t titleIndex = 255;
1254 uint8_t subIndex = 255;
1256 ForcedType_t forcedType = NO_FORCED_TYPE;
1258 context.stepCallback = NULL;
1259 switch (context.type) {
1260 case STREAMING_START_REVIEW_USE_CASE:
1262 titleIndex = reviewPages++;
1263 if (context.review.reviewSubTitle) {
1265 subIndex = reviewPages++;
1268 if (context.currentPage >= reviewPages) {
1273 if (context.currentPage == titleIndex) {
1275 icon = context.review.icon;
1276 text = context.review.reviewTitle;
1278 else if (context.currentPage == subIndex) {
1280 text = context.review.reviewSubTitle;
1284 case STREAMING_CONTINUE_REVIEW_USE_CASE:
1285 if (context.currentPage >= context.review.tagValueList->nbPairs) {
1292 if ((context.review.skipCallback != NULL) && (context.review.skipDisplay ==
false)
1293 && ((context.review.nbDataSets > 1) || (context.currentPage > 0)
1297 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1300 info.
icon = &C_Information_circle_14px;
1301 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1304 context.review.skipDisplay =
true;
1307 context.review.skipDisplay =
false;
1308 bool isCenteredInfo =
false;
1309 getPairData(context.review.tagValueList,
1310 context.currentPage,
1316 if (extension != NULL) {
1317 forcedType = FORCE_BUTTON;
1320 if (isCenteredInfo) {
1321 forcedType = FORCE_CENTERED_INFO;
1326 case STREAMING_FINISH_REVIEW_USE_CASE:
1328 if (context.currentPage == 0) {
1330 getLastPageInfo(
true, &icon, &text);
1334 getLastPageInfo(
false, &icon, &text);
1339 drawStep(pos, icon, text, subText, streamingReviewCallback,
false, forcedType);
1346 const char *text = NULL;
1347 const char *subText = NULL;
1350 context.stepCallback = NULL;
1352 if (context.currentPage < (context.nbPages - 1)) {
1354 ((
const char *
const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
1356 ((
const char *
const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
1359 icon = &C_icon_back_x;
1361 context.stepCallback = startUseCaseHome;
1364 drawStep(pos, icon, text, subText, infoCallback,
false, FORCE_CENTERED_INFO);
1369static void getContentPage(
bool toogle_state, PageContent_t *contentPage)
1371 uint8_t elemIdx = 0;
1375#ifdef WITH_HORIZONTAL_CHOICES_LIST
1377 char **names = NULL;
1379#ifdef WITH_HORIZONTAL_BARS_LIST
1381 char **texts = NULL;
1383 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
1384 if (p_content == NULL) {
1387 switch (p_content->
type) {
1401 &contentPage->subText,
1402 &contentPage->extension,
1404 &contentPage->isCenteredInfo);
1407 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
1411 &contentPage->subText,
1412 &contentPage->extension,
1414 &contentPage->isCenteredInfo);
1418 contentPage->icon = &C_icon_validate_14;
1419 contentPage->isAction =
true;
1423 contentPage->isSwitch =
true;
1426 contentPage->
text = contentSwitch->
text;
1427 contentPage->state = contentSwitch->
initState;
1431 context.stepCallback = onSwitchAction;
1432 contentPage->subText = contentSwitch->
subText;
1437 contentPage->subText
1441#ifdef WITH_HORIZONTAL_CHOICES_LIST
1443 names = (
char **) PIC(contentChoices->
names);
1444 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1445 contentPage->text = PIC(context.content.title);
1446 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1448 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1449 contentPage->text = PIC(context.home.appName);
1450 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1453 contentPage->text = (
const char *) PIC(names[elemIdx]);
1458#ifdef WITH_HORIZONTAL_BARS_LIST
1460 texts = (
char **) PIC(contentBars->
barTexts);
1461 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1462 contentPage->text = PIC(context.content.title);
1463 contentPage->subText = PIC(texts[elemIdx]);
1465 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1466 contentPage->text = PIC(context.home.appName);
1467 contentPage->subText = PIC(texts[elemIdx]);
1470 contentPage->text = PIC(texts[elemIdx]);
1482 PageContent_t contentPage = {0};
1484 context.stepCallback = NULL;
1486 if (context.currentPage < (context.nbPages - 1)) {
1487 getContentPage(toogle_state, &contentPage);
1490 contentPage.icon = &C_icon_back_x;
1491 contentPage.text =
"Back";
1492 if (context.type == GENERIC_SETTINGS) {
1493 context.stepCallback = context.home.quitCallback;
1496 context.stepCallback = startUseCaseHome;
1500 if (contentPage.isSwitch) {
1502 pos, contentPage.text, contentPage.subText, contentPage.state, settingsCallback,
false);
1508 contentPage.subText,
1517static void startUseCaseHome(
void)
1519 switch (context.type) {
1520 case SETTINGS_USE_CASE:
1522 context.currentPage = 1;
1523 if (context.home.homeAction) {
1525 context.currentPage++;
1530 context.currentPage = 1;
1531 if (context.home.homeAction) {
1533 context.currentPage++;
1535 if (context.home.settingContents) {
1537 context.currentPage++;
1542 context.currentPage = 0;
1546 context.type = HOME_USE_CASE;
1547 context.nbPages = 2;
1548 if (context.home.settingContents) {
1551 if (context.home.infosList) {
1554 if (context.home.homeAction) {
1560static void startUseCaseInfo(
void)
1562 context.type = INFO_USE_CASE;
1563 context.nbPages = context.home.infosList->nbInfos + 1;
1564 context.currentPage = 0;
1569static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1575 if (context.type != GENERIC_SETTINGS) {
1576 context.
type = SETTINGS_USE_CASE;
1579 context.nbPages = 1;
1580 for (uint i = 0; i < context.home.settingContents->nbContents; i++) {
1581 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1582 context.nbPages += getContentNbElement(p_content);
1584 context.currentPage = initSettingPage;
1589static void startUseCaseSettings(
void)
1591 startUseCaseSettingsAtPage(0);
1594static void startUseCaseContent(
void)
1596 uint8_t contentIdx = 0;
1600 context.nbPages = 1;
1602 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1603 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1604 context.nbPages += getContentNbElement(p_content);
1608 if (context.currentPage >= context.nbPages) {
1618 const char *text = NULL;
1619 const char *subText = NULL;
1621 uint8_t currentIndex = 0;
1622 uint8_t homeIndex = 255;
1623 uint8_t actionIndex = 255;
1624 uint8_t settingsIndex = 255;
1625 uint8_t infoIndex = 255;
1627 context.stepCallback = NULL;
1630 homeIndex = currentIndex++;
1631 if (context.home.homeAction) {
1632 actionIndex = currentIndex++;
1634 if (context.home.settingContents) {
1635 settingsIndex = currentIndex++;
1637 if (context.home.infosList) {
1638 infoIndex = currentIndex++;
1641 if (context.currentPage == homeIndex) {
1643 icon = context.home.appIcon;
1644 if (context.home.tagline != NULL) {
1645 text = context.home.tagline;
1648 text = context.home.appName;
1649 subText =
"app is ready";
1652 else if (context.currentPage == actionIndex) {
1654 icon = context.home.homeAction->icon;
1655 text = PIC(context.home.homeAction->text);
1656 context.stepCallback = context.home.homeAction->callback;
1658 else if (context.currentPage == settingsIndex) {
1660 icon = &C_icon_coggle;
1661 text =
"App settings";
1662 context.stepCallback = startUseCaseSettings;
1664 else if (context.currentPage == infoIndex) {
1666 icon = &C_Information_circle_14px;
1668 context.stepCallback = startUseCaseInfo;
1671 icon = &C_Quit_14px;
1673 context.stepCallback = context.home.quitCallback;
1676 drawStep(pos, icon, text, subText, homeCallback,
false, NO_FORCED_TYPE);
1683 const char *text = NULL;
1684 const char *subText = NULL;
1687 uint8_t acceptPage = 0;
1689 if (context.choice.message != NULL) {
1690 if ((context.choice.icon == NULL) || (context.choice.subMessage == NULL)) {
1697 context.stepCallback = NULL;
1699 if (context.currentPage < acceptPage) {
1700 if (context.currentPage == 0) {
1701 text = context.choice.message;
1702 if (context.choice.icon != NULL) {
1703 icon = context.choice.icon;
1706 subText = context.choice.subMessage;
1709 else if ((acceptPage == 2) && (context.currentPage == 1)) {
1711 text = context.choice.message;
1712 subText = context.choice.subMessage;
1715 else if (context.currentPage == acceptPage) {
1716 icon = &C_icon_validate_14;
1717 text = context.choice.confirmText;
1718 context.stepCallback = onChoiceAccept;
1720 else if (context.currentPage == (acceptPage + 1)) {
1721 icon = &C_icon_crossmark;
1722 text = context.choice.cancelText;
1723 context.stepCallback = onChoiceReject;
1725 else if (context.choice.details != NULL) {
1728 text = context.choice.details->barList.texts[context.currentPage - (acceptPage + 2)];
1730 = context.choice.details->barList.subTexts[context.currentPage - (acceptPage + 2)];
1734 drawStep(pos, icon, text, subText, genericChoiceCallback,
false, NO_FORCED_TYPE);
1741 const char *text = NULL;
1742 const char *subText = NULL;
1745 context.stepCallback = NULL;
1746 switch (context.currentPage) {
1749 text = context.confirm.message;
1750 subText = context.confirm.subMessage;
1754 icon = &C_icon_validate_14;
1755 text = context.confirm.confirmText;
1756 context.stepCallback = onConfirmAccept;
1760 icon = &C_icon_crossmark;
1761 text = context.confirm.cancelText;
1762 context.stepCallback = onConfirmReject;
1766 drawStep(pos, icon, text, subText, genericConfirmCallback,
true, NO_FORCED_TYPE);
1773 PageContent_t contentPage = {0};
1774 ForcedType_t forcedType = NO_FORCED_TYPE;
1776 context.stepCallback = NULL;
1778 if (context.currentPage < (context.nbPages - 1)) {
1779 getContentPage(toogle_state, &contentPage);
1780 if (contentPage.isCenteredInfo) {
1781 forcedType = FORCE_CENTERED_INFO;
1783 context.forceAction = contentPage.isAction;
1786 if (context.content.rejectText) {
1787 contentPage.text = context.content.rejectText;
1790 contentPage.text =
"Back";
1792 if (context.type == GENERIC_REVIEW_USE_CASE) {
1793 contentPage.icon = &C_icon_crossmark;
1796 contentPage.icon = &C_icon_back_x;
1798 context.stepCallback = context.content.quitCallback;
1801 if (contentPage.isSwitch) {
1803 pos, contentPage.text, contentPage.subText, contentPage.state, contentCallback,
false);
1809 contentPage.subText,
1814 context.forceAction =
false;
1818static void displaySpinner(
const char *text)
1820 drawStep(
SINGLE_STEP, &C_icon_processing, text, NULL, NULL,
false,
false);
1825static void useCaseReview(ContextType_t type,
1829 const char *reviewTitle,
1830 const char *reviewSubTitle,
1831 const char *finishTitle,
1834 memset(&context, 0,
sizeof(UseCaseContext_t));
1835 context.type = type;
1836 context.operationType = operationType;
1837 context.review.tagValueList = tagValueList;
1838 context.review.reviewTitle = reviewTitle;
1839 context.review.reviewSubTitle = reviewSubTitle;
1840 context.review.finishTitle = finishTitle;
1841 context.review.icon = icon;
1842 context.review.onChoice = choiceCallback;
1843 context.currentPage = 0;
1845 context.nbPages = tagValueList->
nbPairs + 3;
1846 if (reviewSubTitle) {
1854static void setPinCodeText(
void)
1856 bool enableValidate =
false;
1857 bool enableBackspace =
true;
1860 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
1862 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
1864 context.keypad.hidden,
1865 context.keypad.pinLen,
1866 (
const char *) context.keypad.pinEntry);
1868 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
1874static void keypadCallback(
char touchedKey)
1876 switch (touchedKey) {
1878 if (context.keypad.pinLen > 0) {
1879 context.keypad.pinLen--;
1880 context.keypad.pinEntry[context.keypad.pinLen] = 0;
1882 else if (context.keypad.backCallback != NULL) {
1883 context.keypad.backCallback();
1890 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
1894 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1895 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
1896 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
1897 context.keypad.pinLen++;
1910 const char **buttons;
1911 int firstButtonToken;
1912 uint8_t nbUsedButtons;
1915} savedKeyboardContext;
1930static void displaySuggestionSelection(
void)
1932 char title[20] = {0};
1934 savedKeyboardContext.buttons = context.keyboard.content.suggestionButtons.buttons;
1935 savedKeyboardContext.firstButtonToken
1936 = context.keyboard.content.suggestionButtons.firstButtonToken;
1937 savedKeyboardContext.nbUsedButtons = context.keyboard.content.suggestionButtons.nbUsedButtons;
1938 savedKeyboardContext.onButtonCallback = context.keyboard.onButtonCallback;
1939 savedKeyboardContext.backCallback = context.keyboard.backCallback;
1943 context.keyboard.layoutCtx = NULL;
1945 snprintf(title,
sizeof(title),
"Select word #%d", context.keyboard.content.number);
1949 savedKeyboardContext.backCallback,
1950 suggestionNavCallback,
1951 savedKeyboardContext.onButtonCallback);
1955static void keyboardCallback(
char touchedKey)
1958 size_t textLen = strlen(context.keyboard.entryBuffer);
1959 PRINTF(
"[keyboardCallback] touchedKey: '%c'\n", touchedKey);
1963 context.keyboard.backCallback();
1966 context.keyboard.entryBuffer[--textLen] =
'\0';
1969 context.keyboard.actionCallback();
1973 context.keyboard.entryBuffer[textLen] = touchedKey;
1974 context.keyboard.entryBuffer[++textLen] =
'\0';
1979 context.keyboard.getSuggestButtons(&context.keyboard.content, &mask);
1980 if ((context.keyboard.content.suggestionButtons.nbUsedButtons > 0)
1981 && (context.keyboard.content.suggestionButtons.nbUsedButtons
1982 < NB_MAX_SUGGESTION_BUTTONS)) {
1985 displaySuggestionSelection();
1989 else if (textLen >= context.keyboard.entryMaxLen) {
1995 context.keyboard.layoutCtx, context.keyboard.textIndex, context.keyboard.entryBuffer);
2001static void launchReviewAfterWarning(
void)
2003 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
2004 useCaseReview(reviewWithWarnCtx.type,
2005 reviewWithWarnCtx.operationType,
2006 reviewWithWarnCtx.tagValueList,
2007 reviewWithWarnCtx.icon,
2008 reviewWithWarnCtx.reviewTitle,
2009 reviewWithWarnCtx.reviewSubTitle,
2010 reviewWithWarnCtx.finishTitle,
2011 reviewWithWarnCtx.choiceCallback);
2013 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
2025 if (reviewWithWarnCtx.warningPage > 0) {
2026 reviewWithWarnCtx.warningPage--;
2031 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
2032 reviewWithWarnCtx.warningPage++;
2034 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2035 && (reviewWithWarnCtx.warning->info != NULL)) {
2036 launchReviewAfterWarning();
2043 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2044 launchReviewAfterWarning();
2047 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2048 reviewWithWarnCtx.choiceCallback(
false);
2055 displayWarningStep();
2059static void displayWarningStep(
void)
2063 if ((reviewWithWarnCtx.warning->prelude) && (reviewWithWarnCtx.warningPage == 0)) {
2068 reviewWithWarnCtx.warning->prelude->title,
2069 reviewWithWarnCtx.warning->prelude->description,
2076 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2078 info.
icon = &C_icon_warning;
2079 info.
text1 =
"Blind signing ahead";
2080 info.
text2 =
"To accept risk, press both buttons";
2081 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2085 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2086 getLastPageInfo(
false, &info.
icon, &info.
text1);
2090 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2091 && (reviewWithWarnCtx.warning->info != NULL)) {
2092 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2093 info.
icon = reviewWithWarnCtx.warning->info->icon;
2094 info.
text1 = reviewWithWarnCtx.warning->info->title;
2095 info.
text2 = reviewWithWarnCtx.warning->info->description;
2096 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2100 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2102 info.
icon = reviewWithWarnCtx.warning->introDetails->centeredInfo.icon;
2103 info.
text1 = reviewWithWarnCtx.warning->introDetails->centeredInfo.title;
2104 info.
text2 = reviewWithWarnCtx.warning->introDetails->centeredInfo.description;
2117 info.
style = BOLD_TEXT1_INFO;
2123static void displayInitialWarning(
void)
2126 reviewWithWarnCtx.warningPage = 0;
2128 || ((reviewWithWarnCtx.warning->introDetails)
2130 reviewWithWarnCtx.nbWarningPages = 2;
2134 reviewWithWarnCtx.nbWarningPages = 1;
2137 reviewWithWarnCtx.firstWarningPage = 0;
2138 displayWarningStep();
2142static void displayPrelude(
void)
2145 reviewWithWarnCtx.warningPage = 0;
2147 || ((reviewWithWarnCtx.warning->introDetails)
2149 reviewWithWarnCtx.nbWarningPages = 3;
2153 reviewWithWarnCtx.nbWarningPages = 2;
2155 reviewWithWarnCtx.firstWarningPage = 1;
2156 displayWarningStep();
2177 bool *requireSpecificDisplay)
2180 UNUSED(tagValueList);
2182 *requireSpecificDisplay =
true;
2202 bool *requireSpecificDisplay)
2205 UNUSED(tagValueList);
2207 UNUSED(isSkippable);
2208 *requireSpecificDisplay =
true;
2246 UNUSED(switchesList);
2286 UNUSED(choicesList);
2300 uint8_t nbPages = 0;
2301 uint8_t nbPairs = tagValueList->
nbPairs;
2302 uint8_t nbPairsInPage;
2306 while (i < tagValueList->nbPairs) {
2310 nbPairs -= nbPairsInPage;
2336 memset(&context, 0,
sizeof(UseCaseContext_t));
2337 context.type = CONTENT_USE_CASE;
2338 context.currentPage = initPage;
2339 context.content.title = title;
2340 context.content.quitCallback = quitCallback;
2341 context.content.navCallback = navCallback;
2342 context.content.controlsCallback = controlsCallback;
2343 context.content.genericContents.callbackCallNeeded =
true;
2344 context.content.genericContents.nbContents = nbPages;
2346 startUseCaseContent();
2365 const char *tagline,
2366 const uint8_t initSettingPage,
2372 memset(&context, 0,
sizeof(UseCaseContext_t));
2373 context.home.appName = appName;
2374 context.home.appIcon = appIcon;
2375 context.home.tagline = tagline;
2376 context.home.settingContents = PIC(settingContents);
2377 context.home.infosList = PIC(infosList);
2378 context.home.homeAction = action;
2379 context.home.quitCallback = quitCallback;
2381 if ((initSettingPage !=
INIT_HOME_PAGE) && (settingContents != NULL)) {
2382 startUseCaseSettingsAtPage(initSettingPage);
2407 memset(&context, 0,
sizeof(UseCaseContext_t));
2408 context.type = GENERIC_SETTINGS;
2409 context.home.appName = appName;
2410 context.home.settingContents = PIC(settingContents);
2411 context.home.infosList = PIC(infosList);
2412 context.home.quitCallback = quitCallback;
2414 startUseCaseSettingsAtPage(initPage);
2453 const char *reviewTitle,
2454 const char *reviewSubTitle,
2455 const char *finishTitle,
2458 useCaseReview(REVIEW_USE_CASE,
2493 const char *reviewTitle,
2494 const char *reviewSubTitle,
2495 const char *finishTitle,
2501 ContextType_t type = REVIEW_USE_CASE;
2504 if ((warning == NULL)
2518 operationType |= NO_THREAT_OPERATION;
2521 operationType |= RISKY_OPERATION;
2524 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
2525 reviewWithWarnCtx.type = type;
2526 reviewWithWarnCtx.operationType = operationType;
2527 reviewWithWarnCtx.tagValueList = tagValueList;
2528 reviewWithWarnCtx.icon = icon;
2529 reviewWithWarnCtx.reviewTitle = reviewTitle;
2530 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2531 reviewWithWarnCtx.finishTitle = finishTitle;
2532 reviewWithWarnCtx.warning = warning;
2533 reviewWithWarnCtx.choiceCallback = choiceCallback;
2536 if (reviewWithWarnCtx.warning->prelude) {
2541 displayInitialWarning();
2577 const char *reviewTitle,
2578 const char *reviewSubTitle,
2579 const char *finishTitle,
2590 &blindSigningWarning,
2611 const char *reviewTitle,
2612 const char *reviewSubTitle,
2613 const char *finishTitle,
2644 const char *reviewTitle,
2645 const char *reviewSubTitle,
2648 memset(&context, 0,
sizeof(UseCaseContext_t));
2649 context.type = ADDRESS_REVIEW_USE_CASE;
2650 context.review.address = address;
2651 context.review.reviewTitle = reviewTitle;
2652 context.review.reviewSubTitle = reviewSubTitle;
2653 context.review.icon = icon;
2654 context.review.onChoice = choiceCallback;
2655 context.currentPage = 0;
2658 context.nbPages = reviewSubTitle ? 5 : 4;
2659 if (additionalTagValueList) {
2660 context.review.tagValueList = PIC(additionalTagValueList);
2661 context.nbPages += additionalTagValueList->
nbPairs;
2676 const char *rejectText,
2679 memset(&context, 0,
sizeof(UseCaseContext_t));
2680 context.type = GENERIC_REVIEW_USE_CASE;
2681 context.content.rejectText = rejectText;
2682 context.content.quitCallback = rejectCallback;
2683 context.content.genericContents.nbContents = contents->
nbContents;
2689 context.content.genericContents.contentsList = PIC(contents->
contentsList);
2692 startUseCaseContent();
2706 memset(&context, 0,
sizeof(UseCaseContext_t));
2707 context.type = STATUS_USE_CASE;
2708 context.stepCallback = quitCallback;
2709 context.currentPage = 0;
2710 context.nbPages = 1;
2716 statusButtonCallback,
2732 switch (reviewStatusType) {
2734 msg =
"Operation signed";
2738 msg =
"Operation rejected";
2742 msg =
"Transaction signed";
2746 msg =
"Transaction rejected";
2750 msg =
"Message signed";
2754 msg =
"Message rejected";
2758 msg =
"Address verified";
2762 msg =
"Address verification cancelled";
2785 const char *reviewTitle,
2786 const char *reviewSubTitle,
2790 streamingOpType = operationType;
2792 memset(&context, 0,
sizeof(UseCaseContext_t));
2793 context.type = STREAMING_START_REVIEW_USE_CASE;
2794 context.operationType = operationType;
2795 context.review.reviewTitle = reviewTitle;
2796 context.review.reviewSubTitle = reviewSubTitle;
2797 context.review.icon = icon;
2798 context.review.onChoice = choiceCallback;
2799 context.currentPage = 0;
2800 context.nbPages = reviewSubTitle ? 3 : 2;
2820 const char *reviewTitle,
2821 const char *reviewSubTitle,
2825 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
2845 const char *reviewTitle,
2846 const char *reviewSubTitle,
2850 memset(&context, 0,
sizeof(UseCaseContext_t));
2851 context.type = STREAMING_START_REVIEW_USE_CASE;
2852 context.operationType = operationType;
2853 context.review.reviewTitle = reviewTitle;
2854 context.review.reviewSubTitle = reviewSubTitle;
2855 context.review.icon = icon;
2856 context.review.onChoice = choiceCallback;
2857 context.currentPage = 0;
2858 context.nbPages = reviewSubTitle ? 3 : 2;
2861 streamingOpType = operationType;
2864 if ((warning == NULL)
2871 operationType |= NO_THREAT_OPERATION;
2874 operationType |= RISKY_OPERATION;
2876 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
2878 reviewWithWarnCtx.type = context.type;
2879 reviewWithWarnCtx.operationType = operationType;
2880 reviewWithWarnCtx.icon = icon;
2881 reviewWithWarnCtx.reviewTitle = reviewTitle;
2882 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2883 reviewWithWarnCtx.choiceCallback = choiceCallback;
2884 reviewWithWarnCtx.warning = warning;
2887 if (reviewWithWarnCtx.warning->prelude) {
2892 displayInitialWarning();
2916 uint8_t curNbDataSets = context.review.nbDataSets;
2918 memset(&context, 0,
sizeof(UseCaseContext_t));
2919 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2920 context.operationType = streamingOpType;
2921 context.review.tagValueList = tagValueList;
2922 context.review.onChoice = choiceCallback;
2923 context.currentPage = 0;
2924 context.nbPages = tagValueList->
nbPairs + 1;
2925 context.review.skipCallback = skipCallback;
2926 context.review.nbDataSets = curNbDataSets + 1;
2950 memset(&context, 0,
sizeof(UseCaseContext_t));
2951 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
2952 context.operationType = streamingOpType;
2953 context.review.onChoice = choiceCallback;
2954 context.review.finishTitle = finishTitle;
2955 context.currentPage = 0;
2956 context.nbPages = 2;
2968 memset(&context, 0,
sizeof(UseCaseContext_t));
2969 context.type = SPINNER_USE_CASE;
2970 context.currentPage = 0;
2971 context.nbPages = 1;
2973 displaySpinner(text);
2989 const char *message,
2990 const char *subMessage,
2991 const char *confirmText,
2992 const char *cancelText,
2996 icon, message, subMessage, confirmText, cancelText, NULL, callback);
3014 const char *message,
3015 const char *subMessage,
3016 const char *confirmText,
3017 const char *cancelText,
3021 memset(&context, 0,
sizeof(UseCaseContext_t));
3022 context.type = CHOICE_USE_CASE;
3023 context.choice.icon = icon;
3024 context.choice.message = message;
3025 context.choice.subMessage = subMessage;
3026 context.choice.confirmText = confirmText;
3027 context.choice.cancelText = cancelText;
3028 context.choice.onChoice = callback;
3029 context.choice.details = details;
3030 context.currentPage = 0;
3031 context.nbPages = 2;
3032 if (message != NULL) {
3035 if ((icon != NULL) && (subMessage != NULL)) {
3039 if (details != NULL) {
3063 const char *subMessage,
3064 const char *confirmText,
3065 const char *cancelText,
3068 memset(&context, 0,
sizeof(UseCaseContext_t));
3069 context.type = CONFIRM_USE_CASE;
3070 context.confirm.message = message;
3071 context.confirm.subMessage = subMessage;
3072 context.confirm.confirmText = confirmText;
3073 context.confirm.cancelText = cancelText;
3074 context.confirm.onConfirm = callback;
3075 context.currentPage = 0;
3076 context.nbPages = 1 + 2;
3091 const char *message,
3092 const char *actionText,
3100 memset(&context, 0,
sizeof(UseCaseContext_t));
3101 context.type = ACTION_USE_CASE;
3102 context.action.actionCallback = callback;
3104 centeredInfo.
icon = icon;
3105 centeredInfo.
text1 = message;
3106 centeredInfo.
style = BOLD_TEXT1_INFO;
3141 memset(&context, 0,
sizeof(KeypadContext_t));
3142 context.type = KEYPAD_USE_CASE;
3143 context.currentPage = 0;
3144 context.nbPages = 1;
3145 context.keypad.validatePin = validatePinCallback;
3146 context.keypad.backCallback = backCallback;
3147 context.keypad.pinMinDigits = minDigits;
3148 context.keypad.pinMaxDigits = maxDigits;
3149 context.keypad.hidden = hidden;
3157 context.keypad.keypadIndex = status;
3165 if (context.keypad.backCallback != NULL) {
3206 .mode = params->
mode,
3212 memset(&context, 0,
sizeof(UseCaseContext_t));
3213 context.type = KEYBOARD_USE_CASE;
3214 context.currentPage = 0;
3215 context.nbPages = 1;
3216 context.keyboard.entryBuffer = PIC(params->
entryBuffer);
3217 context.keyboard.entryMaxLen = params->
entryMaxLen;
3218 context.keyboard.entryBuffer[0] =
'\0';
3220 context.keyboard.content.type = params->
type;
3223 context.keyboard.backCallback = PIC(backCallback);
3225 switch (params->
type) {
3232 context.keyboard.getSuggestButtons
3255 context.keyboard.keyboardIndex = status;
3262 context.keyboard.textIndex = status;
3264 nbgl_layoutAddNavigation(context.keyboard.layoutCtx, &navInfo);
nbgl_contentCenteredInfoStyle_t
possible styles for Centered Info Area
@ 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
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,...)
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
DEPRECATED int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, bool numbered, uint8_t number, const char *text, bool grayedOut, int offsetY, int token)
Adds a "text entry" area under the previously entered object. This area can be preceded (beginning of...
int nbgl_layoutUpdateKeyboard(nbgl_layout_t *layout, uint8_t index, uint32_t keyMask, bool updateCasing, keyboardCase_t casing)
Updates an existing keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInfo)
Creates a keyboard on bottom of the screen, with the given configuration.
@ HORIZONTAL_NAV
'<' and '>' are displayed, to navigate between pages and steps
@ LEFT_ARROW
left arrow is used
@ RIGHT_ARROW
right arrow is used
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_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.
void * nbgl_layout_t
type shared externally
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...
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
@ 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()
DEPRECATED int nbgl_layoutUpdateEnteredText(nbgl_layout_t *layout, uint8_t index, bool numbered, uint8_t number, const char *text, bool grayedOut)
Updates an existing "text entry" area, created with nbgl_layoutAddEnteredText()
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
@ 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)
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)
#define ACTION_ON_ANY_BUTTON
When action callback applies only on both button press.
@ 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
int nbgl_stepRelease(nbgl_step_t step)
#define FORWARD_DIRECTION
When the flow is navigated from last to first step.
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)
nbgl_step_t nbgl_stepDrawCenteredInfo(nbgl_stepPosition_t pos, nbgl_stepButtonCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, nbgl_layoutCenteredInfo_t *info, bool modal)
#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.
@ 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.
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)
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)
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)
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
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)
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)
uint8_t nbBars
number of elements in barTexts and tokens array
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)
bool onTop
if set to true, align only horizontally
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)
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
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
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 ...
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
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
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