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 uint8_t barDetailIdx;
210} ReviewWithWarningContext_t;
221static UseCaseContext_t context;
223static ReviewWithWarningContext_t reviewWithWarnCtx;
241static void displaySpinner(
const char *text);
243static void startUseCaseHome(
void);
244static void startUseCaseInfo(
void);
245static void startUseCaseSettings(
void);
246static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
247static void startUseCaseContent(
void);
249static void statusTickerCallback(
void);
252static void displayWarningStep(
void);
257 switch (content->
type) {
287 if (contentIdx >= genericContents->
nbContents) {
293 if (content == NULL) {
299 if (context.content.navCallback) {
300 if (context.content.navCallback(contentIdx, &pageContent) ==
true) {
303 switch (content->
type) {
352 uint8_t *elemContentIdx,
358 uint8_t elemNbPages = 0;
360 switch (context.type) {
361 case SETTINGS_USE_CASE:
363 case GENERIC_SETTINGS:
364 genericContents = context.home.settingContents;
366 case CONTENT_USE_CASE:
367 case GENERIC_REVIEW_USE_CASE:
368 genericContents = &context.content.genericContents;
373 for (uint i = 0; i < genericContents->
nbContents; i++) {
374 p_content = getContentAtIdx(genericContents, i, content);
375 elemNbPages = getContentNbElement(p_content);
376 if (nbPages + elemNbPages > elemIdx) {
377 *elemContentIdx = context.currentPage - nbPages;
380 nbPages += elemNbPages;
386static const char *getChoiceName(uint8_t choiceIndex)
396 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
397 if (p_content == NULL) {
400 switch (p_content->
type) {
403 names = (
char **) PIC(contentChoices->
names);
408 names = (
char **) PIC(contentBars->
barTexts);
409 nbValues = contentBars->
nbBars;
415 if (choiceIndex >= nbValues) {
419 return (
const char *) PIC(names[choiceIndex]);
422static void onChoiceSelected(uint8_t choiceIndex)
431 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
432 if (p_content == NULL) {
435 switch (p_content->
type) {
438 if (choiceIndex < contentChoices->nbChoices) {
439 token = contentChoices->
token;
444 if (choiceIndex < contentBars->nbBars) {
445 token = contentBars->
tokens[choiceIndex];
452 if ((token != 255) && (context.content.controlsCallback != NULL)) {
453 context.content.controlsCallback(token, 0);
455 else if (context.content.quitCallback != NULL) {
456 context.content.quitCallback();
466 bool *isCenteredInfo)
470 if (tagValueList->
pairs != NULL) {
471 pair = PIC(&tagValueList->
pairs[index]);
474 pair = PIC(tagValueList->
callback(index));
477 *value = pair->
value;
482 *isCenteredInfo =
true;
490static void onReviewAccept(
void)
492 if (context.review.onChoice) {
493 context.review.onChoice(
true);
497static void onReviewReject(
void)
499 if (context.review.onChoice) {
500 context.review.onChoice(
false);
504static void onChoiceAccept(
void)
506 if (context.choice.onChoice) {
507 context.choice.onChoice(
true);
511static void onChoiceReject(
void)
513 if (context.choice.onChoice) {
514 context.choice.onChoice(
false);
518static void onConfirmAccept(
void)
520 if (context.confirm.currentStep) {
523 if (context.confirm.onConfirm) {
524 context.confirm.onConfirm();
528static void onConfirmReject(
void)
530 if (context.confirm.currentStep) {
537static void onSwitchAction(
void)
544 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
550 switch (context.type) {
551 case SETTINGS_USE_CASE:
553 case GENERIC_SETTINGS:
556 case CONTENT_USE_CASE:
557 case GENERIC_REVIEW_USE_CASE:
565 actionCallback(contentSwitch->
token,
567 context.currentPage);
569 else if (context.content.controlsCallback != NULL) {
570 context.content.controlsCallback(contentSwitch->
token, 0);
580 ForcedType_t forcedType)
591 .tickerIntervale = 0,
597 if ((context.type == STREAMING_CONTINUE_REVIEW_USE_CASE)
598 && (context.review.skipCallback != NULL) && (context.review.nbDataSets > 1)) {
601 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
604 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
609 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
611 switch (p_content->
type) {
633 else if ((icon == NULL) && (forcedType != FORCE_CENTERED_INFO)) {
635 if (subTxt != NULL) {
636 style = (forcedType == FORCE_BUTTON) ? BUTTON_INFO : BOLD_TEXT1_INFO;
639 style = REGULAR_INFO;
641 newStep =
nbgl_stepDrawText(pos, onActionCallback, p_ticker, txt, subTxt, style, modal);
649 if ((subTxt != NULL) || (context.stepCallback != NULL) || context.forceAction) {
650 info.
style = BOLD_TEXT1_INFO;
653 info.
style = REGULAR_INFO;
657 if (context.type == CONFIRM_USE_CASE) {
658 context.confirm.currentStep = newStep;
664 const char *description,
673 switchInfo.
text = title;
674 switchInfo.
subText = description;
687 if (context.currentPage > 0) {
688 context.currentPage--;
692 else if ((context.type != STREAMING_CONTINUE_REVIEW_USE_CASE)
693 || (context.review.skipCallback == NULL) || (context.review.nbDataSets == 1)) {
700 if (context.currentPage < (
int) (context.nbPages - 1)) {
701 context.currentPage++;
711 if (context.stepCallback != NULL) {
712 context.stepCallback();
714 else if ((context.type == CONTENT_USE_CASE) || (context.type == SETTINGS_USE_CASE)
715 || (context.type == GENERIC_SETTINGS)
716 || (context.type == GENERIC_REVIEW_USE_CASE)) {
717 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
718 if (p_content != NULL) {
719 switch (p_content->
type) {
734 index = context.currentPage;
739 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
751 else if (context.content.controlsCallback != NULL) {
752 context.content.controlsCallback(token, index);
767 if (!buttonGenericCallback(event, &pos)) {
772 context.review.dataDirection = pos;
774 displayReviewPage(pos);
786 && (context.currentPage > context.firstPairPage)) {
787 context.currentPage--;
794 && (context.currentPage < (
int) (context.nbPages - 1))
795 && (context.currentPage > context.firstPairPage)) {
796 context.currentPage++;
802 if (context.firstPairPage == 0) {
804 context.review.skipCallback();
808 context.currentPage = context.nbPages - 2;
817 if (context.firstPairPage == 0) {
818 displayStreamingReviewPage(pos);
821 displayReviewPage(pos);
831 context.action.actionCallback();
840 if (!buttonGenericCallback(event, &pos)) {
845 context.review.dataDirection = pos;
848 displayStreamingReviewPage(pos);
856 if (!buttonGenericCallback(event, &pos)) {
860 displaySettingsPage(pos,
false);
868 if (!buttonGenericCallback(event, &pos)) {
872 displayInfoPage(pos);
880 if (!buttonGenericCallback(event, &pos)) {
884 displayHomePage(pos);
892 if (!buttonGenericCallback(event, &pos)) {
896 displayChoicePage(pos);
904 if (!buttonGenericCallback(event, &pos)) {
917 if (context.stepCallback != NULL) {
918 context.stepCallback();
928 if (!buttonGenericCallback(event, &pos)) {
932 displayContent(pos,
false);
936static void statusTickerCallback(
void)
938 if (context.stepCallback != NULL) {
939 context.stepCallback();
951 if (context.review.currentExtensionPage > 0) {
952 context.review.currentExtensionPage--;
958 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
959 context.review.currentExtensionPage++;
965 if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
975 displayExtensionStep(pos);
984 const char *text = NULL;
985 const char *subText = NULL;
987 if (context.review.extensionStepCtx != NULL) {
990 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
991 if (context.review.currentExtensionPage == 0) {
998 switch (context.review.extension->aliasType) {
1000 text = context.review.extension->title;
1001 subText = context.review.extension->fullValue;
1004 infoList = context.review.extension->infolist;
1005 text = PIC(infoList->
infoTypes[context.review.currentExtensionPage]);
1006 subText = PIC(infoList->
infoContents[context.review.currentExtensionPage]);
1009 tagValueList = context.review.extension->tagValuelist;
1010 text = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
item);
1011 subText = PIC(tagValueList->
pairs[context.review.currentExtensionPage].
value);
1018 pos, extensionNavigate, NULL, text, subText, BOLD_TEXT1_INFO,
true);
1021 else if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
1023 info.
icon = &C_icon_back_x;
1024 info.
text1 =
"Back";
1025 info.
style = BOLD_TEXT1_INFO;
1027 context.review.extensionStepCtx
1033static void displayAliasFullValue(
void)
1035 const char *text = NULL;
1036 const char *subText = NULL;
1038 bool isCenteredInfo;
1040 getPairData(context.review.tagValueList,
1041 context.review.currentTagValueIndex,
1044 &context.review.extension,
1047 if (context.review.extension == NULL) {
1050 "displayAliasFullValue: extension nor found for pair %d\n",
1051 context.review.currentTagValueIndex);
1054 context.review.currentExtensionPage = 0;
1055 context.review.extensionStepCtx = NULL;
1057 switch (context.review.extension->aliasType) {
1059 context.review.nbExtensionPages = 2;
1062 context.review.nbExtensionPages = context.review.extension->infolist->nbInfos + 1;
1065 context.review.nbExtensionPages = context.review.extension->tagValuelist->nbPairs + 1;
1069 "displayAliasFullValue: unsupported alias type %d\n",
1070 context.review.extension->aliasType);
1076static void getLastPageInfo(
bool approve,
const nbgl_icon_details_t **icon,
const char **text)
1080 *icon = &C_icon_validate_14;
1081 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1086 if (context.review.finishTitle != NULL) {
1087 *text = context.review.finishTitle;
1092 if (context.operationType & RISKY_OPERATION) {
1093 *text =
"Accept risk and sign transaction";
1096 *text =
"Sign transaction";
1100 if (context.operationType & RISKY_OPERATION) {
1101 *text =
"Accept risk and sign message";
1104 *text =
"Sign message";
1108 if (context.operationType & RISKY_OPERATION) {
1109 *text =
"Accept risk and sign operation";
1112 *text =
"Sign operation";
1118 context.stepCallback = onReviewAccept;
1122 *icon = &C_icon_crossmark;
1123 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1127 *text =
"Reject transaction";
1130 *text =
"Reject message";
1133 *text =
"Reject operation";
1135 context.stepCallback = onReviewReject;
1142 uint8_t reviewPages = 0;
1143 uint8_t finalPages = 0;
1144 uint8_t pairIndex = 0;
1145 const char *text = NULL;
1146 const char *subText = NULL;
1148 uint8_t currentIndex = 0;
1149 uint8_t titleIndex = 255;
1150 uint8_t subIndex = 255;
1151 uint8_t approveIndex = 255;
1152 uint8_t rejectIndex = 255;
1154 ForcedType_t forcedType = NO_FORCED_TYPE;
1156 context.stepCallback = NULL;
1160 titleIndex = currentIndex++;
1162 if (context.review.reviewSubTitle) {
1164 subIndex = currentIndex++;
1167 approveIndex = context.nbPages - 2;
1168 rejectIndex = context.nbPages - 1;
1169 finalPages = approveIndex;
1172 if (context.currentPage >= finalPages) {
1173 if (context.currentPage == approveIndex) {
1175 getLastPageInfo(
true, &icon, &text);
1177 else if (context.currentPage == rejectIndex) {
1179 getLastPageInfo(
false, &icon, &text);
1182 else if (context.currentPage < reviewPages) {
1183 if (context.currentPage == titleIndex) {
1185 icon = context.review.icon;
1186 text = context.review.reviewTitle;
1188 else if (context.currentPage == subIndex) {
1190 text = context.review.reviewSubTitle;
1193 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
1196 subText = context.review.address;
1202 if ((context.operationType &
SKIPPABLE_OPERATION) && (context.review.skipDisplay ==
false)
1203 && ((context.currentPage > reviewPages)
1207 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1210 info.
icon = &C_Information_circle_14px;
1211 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1214 context.review.skipDisplay =
true;
1215 context.firstPairPage = reviewPages;
1218 context.review.skipDisplay =
false;
1219 bool isCenteredInfo =
false;
1220 pairIndex = context.currentPage - reviewPages;
1221 if (context.review.address != NULL) {
1224 getPairData(context.review.tagValueList,
1231 if (extension != NULL) {
1232 context.stepCallback = displayAliasFullValue;
1233 context.review.currentTagValueIndex = pairIndex;
1234 forcedType = FORCE_BUTTON;
1237 if (isCenteredInfo) {
1238 forcedType = FORCE_CENTERED_INFO;
1243 drawStep(pos, icon, text, subText, reviewCallback,
false, forcedType);
1250 const char *text = NULL;
1251 const char *subText = NULL;
1253 uint8_t reviewPages = 0;
1254 uint8_t titleIndex = 255;
1255 uint8_t subIndex = 255;
1257 ForcedType_t forcedType = NO_FORCED_TYPE;
1259 context.stepCallback = NULL;
1260 switch (context.type) {
1261 case STREAMING_START_REVIEW_USE_CASE:
1263 titleIndex = reviewPages++;
1264 if (context.review.reviewSubTitle) {
1266 subIndex = reviewPages++;
1269 if (context.currentPage >= reviewPages) {
1274 if (context.currentPage == titleIndex) {
1276 icon = context.review.icon;
1277 text = context.review.reviewTitle;
1279 else if (context.currentPage == subIndex) {
1281 text = context.review.reviewSubTitle;
1285 case STREAMING_CONTINUE_REVIEW_USE_CASE:
1286 if (context.currentPage >= context.review.tagValueList->nbPairs) {
1293 if ((context.review.skipCallback != NULL) && (context.review.skipDisplay ==
false)
1294 && ((context.review.nbDataSets > 1) || (context.currentPage > 0)
1298 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1301 info.
icon = &C_Information_circle_14px;
1302 info.
text1 =
"Press right button to continue message or \bpress both to skip\b";
1305 context.review.skipDisplay =
true;
1308 context.review.skipDisplay =
false;
1309 bool isCenteredInfo =
false;
1310 getPairData(context.review.tagValueList,
1311 context.currentPage,
1317 if (extension != NULL) {
1318 forcedType = FORCE_BUTTON;
1321 if (isCenteredInfo) {
1322 forcedType = FORCE_CENTERED_INFO;
1327 case STREAMING_FINISH_REVIEW_USE_CASE:
1329 if (context.currentPage == 0) {
1331 getLastPageInfo(
true, &icon, &text);
1335 getLastPageInfo(
false, &icon, &text);
1340 drawStep(pos, icon, text, subText, streamingReviewCallback,
false, forcedType);
1347 const char *text = NULL;
1348 const char *subText = NULL;
1351 context.stepCallback = NULL;
1353 if (context.currentPage < (context.nbPages - 1)) {
1355 ((
const char *
const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
1357 ((
const char *
const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
1360 icon = &C_icon_back_x;
1362 context.stepCallback = startUseCaseHome;
1365 drawStep(pos, icon, text, subText, infoCallback,
false, FORCE_CENTERED_INFO);
1370static void getContentPage(
bool toogle_state, PageContent_t *contentPage)
1372 uint8_t elemIdx = 0;
1376#ifdef WITH_HORIZONTAL_CHOICES_LIST
1378 char **names = NULL;
1380#ifdef WITH_HORIZONTAL_BARS_LIST
1382 char **texts = NULL;
1384 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
1385 if (p_content == NULL) {
1388 switch (p_content->
type) {
1402 &contentPage->subText,
1403 &contentPage->extension,
1405 &contentPage->isCenteredInfo);
1408 if (elemIdx < p_content->content.tagValueConfirm.tagValueList.nbPairs) {
1412 &contentPage->subText,
1413 &contentPage->extension,
1415 &contentPage->isCenteredInfo);
1419 contentPage->icon = &C_icon_validate_14;
1420 contentPage->isAction =
true;
1424 contentPage->isSwitch =
true;
1427 contentPage->
text = contentSwitch->
text;
1428 contentPage->state = contentSwitch->
initState;
1432 context.stepCallback = onSwitchAction;
1433 contentPage->subText = contentSwitch->
subText;
1438 contentPage->subText
1442#ifdef WITH_HORIZONTAL_CHOICES_LIST
1444 names = (
char **) PIC(contentChoices->
names);
1445 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1446 contentPage->text = PIC(context.content.title);
1447 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1449 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1450 contentPage->text = PIC(context.home.appName);
1451 contentPage->subText = (
const char *) PIC(names[elemIdx]);
1454 contentPage->text = (
const char *) PIC(names[elemIdx]);
1459#ifdef WITH_HORIZONTAL_BARS_LIST
1461 texts = (
char **) PIC(contentBars->
barTexts);
1462 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1463 contentPage->text = PIC(context.content.title);
1464 contentPage->subText = PIC(texts[elemIdx]);
1466 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1467 contentPage->text = PIC(context.home.appName);
1468 contentPage->subText = PIC(texts[elemIdx]);
1471 contentPage->text = PIC(texts[elemIdx]);
1483 PageContent_t contentPage = {0};
1485 context.stepCallback = NULL;
1487 if (context.currentPage < (context.nbPages - 1)) {
1488 getContentPage(toogle_state, &contentPage);
1491 contentPage.icon = &C_icon_back_x;
1492 contentPage.text =
"Back";
1493 if (context.type == GENERIC_SETTINGS) {
1494 context.stepCallback = context.home.quitCallback;
1497 context.stepCallback = startUseCaseHome;
1501 if (contentPage.isSwitch) {
1503 pos, contentPage.text, contentPage.subText, contentPage.state, settingsCallback,
false);
1509 contentPage.subText,
1518static void startUseCaseHome(
void)
1520 switch (context.type) {
1521 case SETTINGS_USE_CASE:
1523 context.currentPage = 1;
1524 if (context.home.homeAction) {
1526 context.currentPage++;
1531 context.currentPage = 1;
1532 if (context.home.homeAction) {
1534 context.currentPage++;
1536 if (context.home.settingContents) {
1538 context.currentPage++;
1543 context.currentPage = 0;
1547 context.type = HOME_USE_CASE;
1548 context.nbPages = 2;
1549 if (context.home.settingContents) {
1552 if (context.home.infosList) {
1555 if (context.home.homeAction) {
1561static void startUseCaseInfo(
void)
1563 context.type = INFO_USE_CASE;
1564 context.nbPages = context.home.infosList->nbInfos + 1;
1565 context.currentPage = 0;
1570static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1576 if (context.type != GENERIC_SETTINGS) {
1577 context.
type = SETTINGS_USE_CASE;
1580 context.nbPages = 1;
1581 for (uint i = 0; i < context.home.settingContents->nbContents; i++) {
1582 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1583 context.nbPages += getContentNbElement(p_content);
1585 context.currentPage = initSettingPage;
1590static void startUseCaseSettings(
void)
1592 startUseCaseSettingsAtPage(0);
1595static void startUseCaseContent(
void)
1597 uint8_t contentIdx = 0;
1601 context.nbPages = 1;
1603 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1604 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1605 context.nbPages += getContentNbElement(p_content);
1609 if (context.currentPage >= context.nbPages) {
1619 const char *text = NULL;
1620 const char *subText = NULL;
1622 uint8_t currentIndex = 0;
1623 uint8_t homeIndex = 255;
1624 uint8_t actionIndex = 255;
1625 uint8_t settingsIndex = 255;
1626 uint8_t infoIndex = 255;
1628 context.stepCallback = NULL;
1631 homeIndex = currentIndex++;
1632 if (context.home.homeAction) {
1633 actionIndex = currentIndex++;
1635 if (context.home.settingContents) {
1636 settingsIndex = currentIndex++;
1638 if (context.home.infosList) {
1639 infoIndex = currentIndex++;
1642 if (context.currentPage == homeIndex) {
1644 icon = context.home.appIcon;
1645 if (context.home.tagline != NULL) {
1646 text = context.home.tagline;
1649 text = context.home.appName;
1650 subText =
"app is ready";
1653 else if (context.currentPage == actionIndex) {
1655 icon = context.home.homeAction->icon;
1656 text = PIC(context.home.homeAction->text);
1657 context.stepCallback = context.home.homeAction->callback;
1659 else if (context.currentPage == settingsIndex) {
1661 icon = &C_icon_coggle;
1662 text =
"App settings";
1663 context.stepCallback = startUseCaseSettings;
1665 else if (context.currentPage == infoIndex) {
1667 icon = &C_Information_circle_14px;
1669 context.stepCallback = startUseCaseInfo;
1672 icon = &C_Quit_14px;
1674 context.stepCallback = context.home.quitCallback;
1677 drawStep(pos, icon, text, subText, homeCallback,
false, NO_FORCED_TYPE);
1684 const char *text = NULL;
1685 const char *subText = NULL;
1688 uint8_t acceptPage = 0;
1690 if (context.choice.message != NULL) {
1691 if ((context.choice.icon == NULL) || (context.choice.subMessage == NULL)) {
1698 context.stepCallback = NULL;
1700 if (context.currentPage < acceptPage) {
1701 if (context.currentPage == 0) {
1702 text = context.choice.message;
1703 if (context.choice.icon != NULL) {
1704 icon = context.choice.icon;
1707 subText = context.choice.subMessage;
1710 else if ((acceptPage == 2) && (context.currentPage == 1)) {
1712 text = context.choice.message;
1713 subText = context.choice.subMessage;
1716 else if (context.currentPage == acceptPage) {
1717 icon = &C_icon_validate_14;
1718 text = context.choice.confirmText;
1719 context.stepCallback = onChoiceAccept;
1721 else if (context.currentPage == (acceptPage + 1)) {
1722 icon = &C_icon_crossmark;
1723 text = context.choice.cancelText;
1724 context.stepCallback = onChoiceReject;
1726 else if (context.choice.details != NULL) {
1729 text = context.choice.details->barList.texts[context.currentPage - (acceptPage + 2)];
1731 = context.choice.details->barList.subTexts[context.currentPage - (acceptPage + 2)];
1735 drawStep(pos, icon, text, subText, genericChoiceCallback,
false, NO_FORCED_TYPE);
1742 const char *text = NULL;
1743 const char *subText = NULL;
1746 context.stepCallback = NULL;
1747 switch (context.currentPage) {
1750 text = context.confirm.message;
1751 subText = context.confirm.subMessage;
1755 icon = &C_icon_validate_14;
1756 text = context.confirm.confirmText;
1757 context.stepCallback = onConfirmAccept;
1761 icon = &C_icon_crossmark;
1762 text = context.confirm.cancelText;
1763 context.stepCallback = onConfirmReject;
1767 drawStep(pos, icon, text, subText, genericConfirmCallback,
true, NO_FORCED_TYPE);
1774 PageContent_t contentPage = {0};
1775 ForcedType_t forcedType = NO_FORCED_TYPE;
1777 context.stepCallback = NULL;
1779 if (context.currentPage < (context.nbPages - 1)) {
1780 getContentPage(toogle_state, &contentPage);
1781 if (contentPage.isCenteredInfo) {
1782 forcedType = FORCE_CENTERED_INFO;
1784 context.forceAction = contentPage.isAction;
1787 if (context.content.rejectText) {
1788 contentPage.text = context.content.rejectText;
1791 contentPage.text =
"Back";
1793 if (context.type == GENERIC_REVIEW_USE_CASE) {
1794 contentPage.icon = &C_icon_crossmark;
1797 contentPage.icon = &C_icon_back_x;
1799 context.stepCallback = context.content.quitCallback;
1802 if (contentPage.isSwitch) {
1804 pos, contentPage.text, contentPage.subText, contentPage.state, contentCallback,
false);
1810 contentPage.subText,
1815 context.forceAction =
false;
1819static void displaySpinner(
const char *text)
1821 drawStep(
SINGLE_STEP, &C_icon_processing, text, NULL, NULL,
false,
false);
1826static void useCaseReview(ContextType_t type,
1830 const char *reviewTitle,
1831 const char *reviewSubTitle,
1832 const char *finishTitle,
1835 memset(&context, 0,
sizeof(UseCaseContext_t));
1836 context.type = type;
1837 context.operationType = operationType;
1838 context.review.tagValueList = tagValueList;
1839 context.review.reviewTitle = reviewTitle;
1840 context.review.reviewSubTitle = reviewSubTitle;
1841 context.review.finishTitle = finishTitle;
1842 context.review.icon = icon;
1843 context.review.onChoice = choiceCallback;
1844 context.currentPage = 0;
1846 context.nbPages = tagValueList->
nbPairs + 3;
1847 if (reviewSubTitle) {
1855static void setPinCodeText(
void)
1857 bool enableValidate =
false;
1858 bool enableBackspace =
true;
1861 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
1863 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
1865 context.keypad.hidden,
1866 context.keypad.pinLen,
1867 (
const char *) context.keypad.pinEntry);
1869 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
1875static void keypadCallback(
char touchedKey)
1877 switch (touchedKey) {
1879 if (context.keypad.pinLen > 0) {
1880 context.keypad.pinLen--;
1881 context.keypad.pinEntry[context.keypad.pinLen] = 0;
1883 else if (context.keypad.backCallback != NULL) {
1884 context.keypad.backCallback();
1891 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
1895 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1896 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
1897 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
1898 context.keypad.pinLen++;
1911 const char **buttons;
1912 int firstButtonToken;
1913 uint8_t nbUsedButtons;
1916} savedKeyboardContext;
1931static void displaySuggestionSelection(
void)
1933 char title[20] = {0};
1935 savedKeyboardContext.buttons = context.keyboard.content.suggestionButtons.buttons;
1936 savedKeyboardContext.firstButtonToken
1937 = context.keyboard.content.suggestionButtons.firstButtonToken;
1938 savedKeyboardContext.nbUsedButtons = context.keyboard.content.suggestionButtons.nbUsedButtons;
1939 savedKeyboardContext.onButtonCallback = context.keyboard.onButtonCallback;
1940 savedKeyboardContext.backCallback = context.keyboard.backCallback;
1944 context.keyboard.layoutCtx = NULL;
1946 snprintf(title,
sizeof(title),
"Select word #%d", context.keyboard.content.number);
1950 savedKeyboardContext.backCallback,
1951 suggestionNavCallback,
1952 savedKeyboardContext.onButtonCallback);
1956static void keyboardCallback(
char touchedKey)
1959 size_t textLen = strlen(context.keyboard.entryBuffer);
1960 PRINTF(
"[keyboardCallback] touchedKey: '%c'\n", touchedKey);
1964 context.keyboard.backCallback();
1967 context.keyboard.entryBuffer[--textLen] =
'\0';
1970 context.keyboard.actionCallback();
1974 context.keyboard.entryBuffer[textLen] = touchedKey;
1975 context.keyboard.entryBuffer[++textLen] =
'\0';
1980 context.keyboard.getSuggestButtons(&context.keyboard.content, &mask);
1981 if ((context.keyboard.content.suggestionButtons.nbUsedButtons > 0)
1982 && (context.keyboard.content.suggestionButtons.nbUsedButtons
1983 < NB_MAX_SUGGESTION_BUTTONS)) {
1986 displaySuggestionSelection();
1990 else if (textLen >= context.keyboard.entryMaxLen) {
1996 context.keyboard.layoutCtx, context.keyboard.textIndex, context.keyboard.entryBuffer);
2002static void launchReviewAfterWarning(
void)
2004 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
2005 useCaseReview(reviewWithWarnCtx.type,
2006 reviewWithWarnCtx.operationType,
2007 reviewWithWarnCtx.tagValueList,
2008 reviewWithWarnCtx.icon,
2009 reviewWithWarnCtx.reviewTitle,
2010 reviewWithWarnCtx.reviewSubTitle,
2011 reviewWithWarnCtx.finishTitle,
2012 reviewWithWarnCtx.choiceCallback);
2014 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
2024 displayWarningStep();
2029static void displayBarDetailStep(
void)
2032 = &reviewWithWarnCtx.warning->introDetails->
barList.
details[reviewWithWarnCtx.barDetailIdx];
2039 info.
style = BOLD_TEXT1_INFO;
2055 if (reviewWithWarnCtx.warningPage > 0) {
2056 reviewWithWarnCtx.warningPage--;
2061 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
2062 reviewWithWarnCtx.warningPage++;
2064 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2065 && (reviewWithWarnCtx.warning->info != NULL)) {
2066 launchReviewAfterWarning();
2073 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2074 launchReviewAfterWarning();
2077 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2078 reviewWithWarnCtx.choiceCallback(
false);
2082 else if ((event ==
BUTTON_BOTH_PRESSED) && (reviewWithWarnCtx.warning->introDetails != NULL)
2084 && (reviewWithWarnCtx.warningPage > reviewWithWarnCtx.firstWarningPage)) {
2086 barIdx = reviewWithWarnCtx.warningPage - reviewWithWarnCtx.firstWarningPage - 1;
2087 if ((reviewWithWarnCtx.warning->introDetails->barList.details != NULL)
2088 && (reviewWithWarnCtx.warning->introDetails->barList.details[barIdx].type
2090 reviewWithWarnCtx.barDetailIdx = barIdx;
2091 displayBarDetailStep();
2098 displayWarningStep();
2102static void displayWarningStep(
void)
2107 if ((reviewWithWarnCtx.warning->prelude) && (reviewWithWarnCtx.warningPage == 0)) {
2112 reviewWithWarnCtx.warning->prelude->title,
2113 reviewWithWarnCtx.warning->prelude->description,
2120 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2122 info.
icon = &C_icon_warning;
2123 info.
text1 =
"Blind signing ahead";
2124 info.
text2 =
"To accept risk, press both buttons";
2125 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2129 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2130 getLastPageInfo(
false, &info.
icon, &info.
text1);
2134 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
2135 && (reviewWithWarnCtx.warning->info != NULL)) {
2136 if (reviewWithWarnCtx.warningPage == reviewWithWarnCtx.firstWarningPage) {
2137 info.
icon = reviewWithWarnCtx.warning->info->icon;
2138 info.
text1 = reviewWithWarnCtx.warning->info->title;
2139 info.
text2 = reviewWithWarnCtx.warning->info->description;
2140 pos = (reviewWithWarnCtx.firstWarningPage == 0) ?
FIRST_STEP
2144 else if ((reviewWithWarnCtx.warning->introDetails != NULL)
2147 barIdx = reviewWithWarnCtx.warningPage - reviewWithWarnCtx.firstWarningPage - 1;
2148 if (reviewWithWarnCtx.warning->introDetails->barList.icons) {
2149 info.
icon = reviewWithWarnCtx.warning->introDetails->barList.icons[barIdx];
2151 info.
text1 = reviewWithWarnCtx.warning->introDetails->barList.texts[barIdx];
2152 if (reviewWithWarnCtx.warning->introDetails->barList.subTexts) {
2153 info.
text2 = reviewWithWarnCtx.warning->introDetails->barList.subTexts[barIdx];
2157 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
2158 if ((reviewWithWarnCtx.warning->introDetails != NULL)
2160 info.
icon = reviewWithWarnCtx.warning->introDetails->centeredInfo.icon;
2161 info.
text1 = reviewWithWarnCtx.warning->introDetails->centeredInfo.title;
2162 info.
text2 = reviewWithWarnCtx.warning->introDetails->centeredInfo.description;
2175 info.
style = BOLD_TEXT1_INFO;
2181static void displayInitialWarning(
void)
2184 reviewWithWarnCtx.warningPage = 0;
2186 || ((reviewWithWarnCtx.warning->introDetails)
2188 reviewWithWarnCtx.nbWarningPages = 2;
2190 else if ((reviewWithWarnCtx.warning->introDetails)
2192 reviewWithWarnCtx.nbWarningPages
2193 = reviewWithWarnCtx.warning->introDetails->barList.nbBars + 1;
2197 reviewWithWarnCtx.nbWarningPages = 1;
2200 reviewWithWarnCtx.firstWarningPage = 0;
2201 displayWarningStep();
2205static void displayPrelude(
void)
2208 reviewWithWarnCtx.warningPage = 0;
2210 || ((reviewWithWarnCtx.warning->introDetails)
2212 reviewWithWarnCtx.nbWarningPages = 3;
2216 reviewWithWarnCtx.nbWarningPages = 2;
2218 reviewWithWarnCtx.firstWarningPage = 1;
2219 displayWarningStep();
2240 bool *requireSpecificDisplay)
2243 UNUSED(tagValueList);
2245 *requireSpecificDisplay =
true;
2265 bool *requireSpecificDisplay)
2268 UNUSED(tagValueList);
2270 UNUSED(isSkippable);
2271 *requireSpecificDisplay =
true;
2309 UNUSED(switchesList);
2349 UNUSED(choicesList);
2363 uint8_t nbPages = 0;
2364 uint8_t nbPairs = tagValueList->
nbPairs;
2365 uint8_t nbPairsInPage;
2369 while (i < tagValueList->nbPairs) {
2373 nbPairs -= nbPairsInPage;
2399 memset(&context, 0,
sizeof(UseCaseContext_t));
2400 context.type = CONTENT_USE_CASE;
2401 context.currentPage = initPage;
2402 context.content.title = title;
2403 context.content.quitCallback = quitCallback;
2404 context.content.navCallback = navCallback;
2405 context.content.controlsCallback = controlsCallback;
2406 context.content.genericContents.callbackCallNeeded =
true;
2407 context.content.genericContents.nbContents = nbPages;
2409 startUseCaseContent();
2428 const char *tagline,
2429 const uint8_t initSettingPage,
2435 memset(&context, 0,
sizeof(UseCaseContext_t));
2436 context.home.appName = appName;
2437 context.home.appIcon = appIcon;
2438 context.home.tagline = tagline;
2439 context.home.settingContents = PIC(settingContents);
2440 context.home.infosList = PIC(infosList);
2441 context.home.homeAction = action;
2442 context.home.quitCallback = quitCallback;
2444 if ((initSettingPage !=
INIT_HOME_PAGE) && (settingContents != NULL)) {
2445 startUseCaseSettingsAtPage(initSettingPage);
2470 memset(&context, 0,
sizeof(UseCaseContext_t));
2471 context.type = GENERIC_SETTINGS;
2472 context.home.appName = appName;
2473 context.home.settingContents = PIC(settingContents);
2474 context.home.infosList = PIC(infosList);
2475 context.home.quitCallback = quitCallback;
2477 startUseCaseSettingsAtPage(initPage);
2516 const char *reviewTitle,
2517 const char *reviewSubTitle,
2518 const char *finishTitle,
2521 useCaseReview(REVIEW_USE_CASE,
2556 const char *reviewTitle,
2557 const char *reviewSubTitle,
2558 const char *finishTitle,
2564 ContextType_t type = REVIEW_USE_CASE;
2567 if ((warning == NULL)
2581 operationType |= NO_THREAT_OPERATION;
2584 operationType |= RISKY_OPERATION;
2587 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
2588 reviewWithWarnCtx.type = type;
2589 reviewWithWarnCtx.operationType = operationType;
2590 reviewWithWarnCtx.tagValueList = tagValueList;
2591 reviewWithWarnCtx.icon = icon;
2592 reviewWithWarnCtx.reviewTitle = reviewTitle;
2593 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2594 reviewWithWarnCtx.finishTitle = finishTitle;
2595 reviewWithWarnCtx.warning = warning;
2596 reviewWithWarnCtx.choiceCallback = choiceCallback;
2599 if (reviewWithWarnCtx.warning->prelude) {
2604 displayInitialWarning();
2640 const char *reviewTitle,
2641 const char *reviewSubTitle,
2642 const char *finishTitle,
2653 &blindSigningWarning,
2674 const char *reviewTitle,
2675 const char *reviewSubTitle,
2676 const char *finishTitle,
2707 const char *reviewTitle,
2708 const char *reviewSubTitle,
2711 memset(&context, 0,
sizeof(UseCaseContext_t));
2712 context.type = ADDRESS_REVIEW_USE_CASE;
2713 context.review.address = address;
2714 context.review.reviewTitle = reviewTitle;
2715 context.review.reviewSubTitle = reviewSubTitle;
2716 context.review.icon = icon;
2717 context.review.onChoice = choiceCallback;
2718 context.currentPage = 0;
2721 context.nbPages = reviewSubTitle ? 5 : 4;
2722 if (additionalTagValueList) {
2723 context.review.tagValueList = PIC(additionalTagValueList);
2724 context.nbPages += additionalTagValueList->
nbPairs;
2739 const char *rejectText,
2742 memset(&context, 0,
sizeof(UseCaseContext_t));
2743 context.type = GENERIC_REVIEW_USE_CASE;
2744 context.content.rejectText = rejectText;
2745 context.content.quitCallback = rejectCallback;
2746 context.content.genericContents.nbContents = contents->
nbContents;
2752 context.content.genericContents.contentsList = PIC(contents->
contentsList);
2755 startUseCaseContent();
2769 memset(&context, 0,
sizeof(UseCaseContext_t));
2770 context.type = STATUS_USE_CASE;
2771 context.stepCallback = quitCallback;
2772 context.currentPage = 0;
2773 context.nbPages = 1;
2779 statusButtonCallback,
2795 switch (reviewStatusType) {
2797 msg =
"Operation signed";
2801 msg =
"Operation rejected";
2805 msg =
"Transaction signed";
2809 msg =
"Transaction rejected";
2813 msg =
"Message signed";
2817 msg =
"Message rejected";
2821 msg =
"Address verified";
2825 msg =
"Address verification cancelled";
2848 const char *reviewTitle,
2849 const char *reviewSubTitle,
2853 streamingOpType = operationType;
2855 memset(&context, 0,
sizeof(UseCaseContext_t));
2856 context.type = STREAMING_START_REVIEW_USE_CASE;
2857 context.operationType = operationType;
2858 context.review.reviewTitle = reviewTitle;
2859 context.review.reviewSubTitle = reviewSubTitle;
2860 context.review.icon = icon;
2861 context.review.onChoice = choiceCallback;
2862 context.currentPage = 0;
2863 context.nbPages = reviewSubTitle ? 3 : 2;
2883 const char *reviewTitle,
2884 const char *reviewSubTitle,
2888 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
2908 const char *reviewTitle,
2909 const char *reviewSubTitle,
2913 memset(&context, 0,
sizeof(UseCaseContext_t));
2914 context.type = STREAMING_START_REVIEW_USE_CASE;
2915 context.operationType = operationType;
2916 context.review.reviewTitle = reviewTitle;
2917 context.review.reviewSubTitle = reviewSubTitle;
2918 context.review.icon = icon;
2919 context.review.onChoice = choiceCallback;
2920 context.currentPage = 0;
2921 context.nbPages = reviewSubTitle ? 3 : 2;
2924 streamingOpType = operationType;
2927 if ((warning == NULL)
2934 operationType |= NO_THREAT_OPERATION;
2937 operationType |= RISKY_OPERATION;
2939 memset(&reviewWithWarnCtx, 0,
sizeof(reviewWithWarnCtx));
2941 reviewWithWarnCtx.type = context.type;
2942 reviewWithWarnCtx.operationType = operationType;
2943 reviewWithWarnCtx.icon = icon;
2944 reviewWithWarnCtx.reviewTitle = reviewTitle;
2945 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2946 reviewWithWarnCtx.choiceCallback = choiceCallback;
2947 reviewWithWarnCtx.warning = warning;
2950 if (reviewWithWarnCtx.warning->prelude) {
2955 displayInitialWarning();
2979 uint8_t curNbDataSets = context.review.nbDataSets;
2981 memset(&context, 0,
sizeof(UseCaseContext_t));
2982 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2983 context.operationType = streamingOpType;
2984 context.review.tagValueList = tagValueList;
2985 context.review.onChoice = choiceCallback;
2986 context.currentPage = 0;
2987 context.nbPages = tagValueList->
nbPairs + 1;
2988 context.review.skipCallback = skipCallback;
2989 context.review.nbDataSets = curNbDataSets + 1;
3013 memset(&context, 0,
sizeof(UseCaseContext_t));
3014 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
3015 context.operationType = streamingOpType;
3016 context.review.onChoice = choiceCallback;
3017 context.review.finishTitle = finishTitle;
3018 context.currentPage = 0;
3019 context.nbPages = 2;
3031 memset(&context, 0,
sizeof(UseCaseContext_t));
3032 context.type = SPINNER_USE_CASE;
3033 context.currentPage = 0;
3034 context.nbPages = 1;
3036 displaySpinner(text);
3052 const char *message,
3053 const char *subMessage,
3054 const char *confirmText,
3055 const char *cancelText,
3059 icon, message, subMessage, confirmText, cancelText, NULL, callback);
3077 const char *message,
3078 const char *subMessage,
3079 const char *confirmText,
3080 const char *cancelText,
3084 memset(&context, 0,
sizeof(UseCaseContext_t));
3085 context.type = CHOICE_USE_CASE;
3086 context.choice.icon = icon;
3087 context.choice.message = message;
3088 context.choice.subMessage = subMessage;
3089 context.choice.confirmText = confirmText;
3090 context.choice.cancelText = cancelText;
3091 context.choice.onChoice = callback;
3092 context.choice.details = details;
3093 context.currentPage = 0;
3094 context.nbPages = 2;
3095 if (message != NULL) {
3098 if ((icon != NULL) && (subMessage != NULL)) {
3102 if (details != NULL) {
3126 const char *subMessage,
3127 const char *confirmText,
3128 const char *cancelText,
3131 memset(&context, 0,
sizeof(UseCaseContext_t));
3132 context.type = CONFIRM_USE_CASE;
3133 context.confirm.message = message;
3134 context.confirm.subMessage = subMessage;
3135 context.confirm.confirmText = confirmText;
3136 context.confirm.cancelText = cancelText;
3137 context.confirm.onConfirm = callback;
3138 context.currentPage = 0;
3139 context.nbPages = 1 + 2;
3154 const char *message,
3155 const char *actionText,
3163 memset(&context, 0,
sizeof(UseCaseContext_t));
3164 context.type = ACTION_USE_CASE;
3165 context.action.actionCallback = callback;
3167 centeredInfo.
icon = icon;
3168 centeredInfo.
text1 = message;
3169 centeredInfo.
style = BOLD_TEXT1_INFO;
3204 memset(&context, 0,
sizeof(KeypadContext_t));
3205 context.type = KEYPAD_USE_CASE;
3206 context.currentPage = 0;
3207 context.nbPages = 1;
3208 context.keypad.validatePin = validatePinCallback;
3209 context.keypad.backCallback = backCallback;
3210 context.keypad.pinMinDigits = minDigits;
3211 context.keypad.pinMaxDigits = maxDigits;
3212 context.keypad.hidden = hidden;
3220 context.keypad.keypadIndex = status;
3228 if (context.keypad.backCallback != NULL) {
3269 .mode = params->
mode,
3275 memset(&context, 0,
sizeof(UseCaseContext_t));
3276 context.type = KEYBOARD_USE_CASE;
3277 context.currentPage = 0;
3278 context.nbPages = 1;
3279 context.keyboard.entryBuffer = PIC(params->
entryBuffer);
3280 context.keyboard.entryMaxLen = params->
entryMaxLen;
3281 context.keyboard.entryBuffer[0] =
'\0';
3283 context.keyboard.content.type = params->
type;
3286 context.keyboard.backCallback = PIC(backCallback);
3288 switch (params->
type) {
3295 context.keyboard.getSuggestButtons
3318 context.keyboard.keyboardIndex = status;
3325 context.keyboard.textIndex = status;
3327 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.
@ 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.
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
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)
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
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