Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_use_case_nanos.c
Go to the documentation of this file.
1
6#ifdef NBGL_USE_CASE
7#ifndef HAVE_SE_TOUCH
8/*********************
9 * INCLUDES
10 *********************/
11#include <string.h>
12#include <stdio.h>
13#include "nbgl_debug.h"
14#include "nbgl_use_case.h"
15#include "glyphs.h"
16#include "os_pic.h"
17#include "os_helpers.h"
18#include "ux.h"
19
20/*********************
21 * DEFINES
22 *********************/
23#define WITH_HORIZONTAL_CHOICES_LIST
24#define WITH_HORIZONTAL_BARS_LIST
25
31#define RISKY_OPERATION (1 << 6)
32
38#define NO_THREAT_OPERATION (1 << 7)
39
40/**********************
41 * TYPEDEFS
42 **********************/
43
44typedef struct ReviewContext_s {
45 nbgl_choiceCallback_t onChoice;
46 const nbgl_contentTagValueList_t *tagValueList;
47 const nbgl_icon_details_t *icon;
48 const char *reviewTitle;
49 const char *reviewSubTitle;
50 const char *finishTitle;
51 const char *address; // for address confirmation review
52 nbgl_callback_t skipCallback; // callback provided by used
53 uint8_t nbDataSets; // number of sets of data received by StreamingContinue
54 bool skipDisplay; // if set to true, means that we are displaying the skip page
55 uint8_t dataDirection; // used to know whether the skip page is reached from back or forward
56 uint8_t currentTagValueIndex;
57 uint8_t currentExtensionPage;
58 uint8_t nbExtensionPages;
59 const nbgl_contentValueExt_t *extension;
60 nbgl_step_t extensionStepCtx;
61
62} ReviewContext_t;
63
64typedef struct ChoiceContext_s {
65 const nbgl_icon_details_t *icon;
66 const char *message;
67 const char *subMessage;
68 const char *confirmText;
69 const char *cancelText;
70 nbgl_choiceCallback_t onChoice;
71 const nbgl_genericDetails_t *details;
72} ChoiceContext_t;
73
74typedef struct ConfirmContext_s {
75 const char *message;
76 const char *subMessage;
77 const char *confirmText;
78 const char *cancelText;
79 nbgl_callback_t onConfirm;
80 nbgl_step_t currentStep;
81} ConfirmContext_t;
82
83typedef struct ContentContext_s {
84 const char *title; // For CHOICES_LIST /BARS_LIST
85 nbgl_genericContents_t genericContents;
86 const char *rejectText;
87 nbgl_layoutTouchCallback_t controlsCallback;
88 nbgl_navCallback_t navCallback;
89 nbgl_callback_t quitCallback;
90} ContentContext_t;
91
92typedef struct HomeContext_s {
93 const char *appName;
94 const nbgl_icon_details_t *appIcon;
95 const char *tagline;
96 const nbgl_genericContents_t *settingContents;
97 const nbgl_contentInfoList_t *infosList;
98 const nbgl_homeAction_t *homeAction;
99 nbgl_callback_t quitCallback;
100} HomeContext_t;
101
102typedef struct ActionContext_s {
103 nbgl_callback_t actionCallback;
104} ActionContext_t;
105
106#ifdef NBGL_KEYPAD
107typedef struct KeypadContext_s {
108 uint8_t pinEntry[8];
109 uint8_t pinLen;
110 uint8_t pinMinDigits;
111 uint8_t pinMaxDigits;
112 nbgl_layout_t *layoutCtx;
113 bool hidden;
114 uint8_t keypadIndex;
115 nbgl_pinValidCallback_t validatePin;
116 nbgl_callback_t backCallback;
117} KeypadContext_t;
118#endif
119
120typedef enum {
121 NONE_USE_CASE,
122 SPINNER_USE_CASE,
123 REVIEW_USE_CASE,
124 GENERIC_REVIEW_USE_CASE,
125 ADDRESS_REVIEW_USE_CASE,
126 STREAMING_START_REVIEW_USE_CASE,
127 STREAMING_CONTINUE_REVIEW_USE_CASE,
128 STREAMING_FINISH_REVIEW_USE_CASE,
129 CHOICE_USE_CASE,
130 STATUS_USE_CASE,
131 CONFIRM_USE_CASE,
132 KEYPAD_USE_CASE,
133 HOME_USE_CASE,
134 INFO_USE_CASE,
135 SETTINGS_USE_CASE,
136 GENERIC_SETTINGS,
137 CONTENT_USE_CASE,
138 ACTION_USE_CASE
139} ContextType_t;
140
141typedef struct UseCaseContext_s {
142 ContextType_t type;
143 nbgl_operationType_t operationType;
144 uint8_t nbPages;
145 int8_t currentPage;
147 stepCallback;
148 union {
149 ReviewContext_t review;
150 ChoiceContext_t choice;
151 ConfirmContext_t confirm;
152 HomeContext_t home;
153 ContentContext_t content;
154#ifdef NBGL_KEYPAD
155 KeypadContext_t keypad;
156#endif
157 ActionContext_t action;
158 };
159} UseCaseContext_t;
160
161typedef struct PageContent_s {
162 bool isSwitch;
163 const char *text;
164 const char *subText;
165 const nbgl_icon_details_t *icon;
166 const nbgl_contentValueExt_t *extension;
167 nbgl_state_t state;
168 bool isCenteredInfo;
169} PageContent_t;
170
171typedef struct ReviewWithWarningContext_s {
172 ContextType_t type;
173 nbgl_operationType_t operationType;
174 const nbgl_contentTagValueList_t *tagValueList;
175 const nbgl_icon_details_t *icon;
176 const char *reviewTitle;
177 const char *reviewSubTitle;
178 const char *finishTitle;
179 const nbgl_warning_t *warning;
180 nbgl_choiceCallback_t choiceCallback;
181 uint8_t securityReportLevel; // level 1 is the first level of menus
182 bool isIntro; // set to true during intro (before actual review)
183 uint8_t warningPage;
184 uint8_t nbWarningPages;
185} ReviewWithWarningContext_t;
186
187typedef enum {
188 NO_FORCED_TYPE = 0,
189 FORCE_BUTTON,
190 FORCE_CENTERED_INFO
191} ForcedType_t;
192
193/**********************
194 * STATIC VARIABLES
195 **********************/
196static UseCaseContext_t context;
197
198static ReviewWithWarningContext_t reviewWithWarnCtx;
199// configuration of warning when using @ref nbgl_useCaseReviewBlindSigning()
200static const nbgl_warning_t blindSigningWarning = {.predefinedSet = (1 << BLIND_SIGNING_WARN)};
201
202// Operation type for streaming (because the one in 'context' is reset at each streaming API call)
203nbgl_operationType_t streamingOpType;
204
205/**********************
206 * STATIC FUNCTIONS
207 **********************/
208static void displayReviewPage(nbgl_stepPosition_t pos);
209static void displayStreamingReviewPage(nbgl_stepPosition_t pos);
210static void displayHomePage(nbgl_stepPosition_t pos);
211static void displayInfoPage(nbgl_stepPosition_t pos);
212static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state);
213static void displayChoicePage(nbgl_stepPosition_t pos);
214static void displayConfirm(nbgl_stepPosition_t pos);
215static void displayContent(nbgl_stepPosition_t pos, bool toogle_state);
216static void displaySpinner(const char *text);
217
218static void startUseCaseHome(void);
219static void startUseCaseInfo(void);
220static void startUseCaseSettings(void);
221static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
222static void startUseCaseContent(void);
223
224static void statusTickerCallback(void);
225
226static void displayExtensionStep(nbgl_stepPosition_t pos);
227static void displayWarningStep(void);
228
229// Simple helper to get the number of elements inside a nbgl_content_t
230static uint8_t getContentNbElement(const nbgl_content_t *content)
231{
232 switch (content->type) {
233 case CENTERED_INFO:
234 return 1;
235 case INFO_BUTTON:
236 return 1;
237 case TAG_VALUE_LIST:
238 return content->content.tagValueList.nbPairs;
239 case SWITCHES_LIST:
240 return content->content.switchesList.nbSwitches;
241 case INFOS_LIST:
242 return content->content.infosList.nbInfos;
243 case CHOICES_LIST:
244 return content->content.choicesList.nbChoices;
245 case BARS_LIST:
246 return content->content.barsList.nbBars;
247 default:
248 return 0;
249 }
250}
251
252// Helper to retrieve the content inside a nbgl_genericContents_t using
253// either the contentsList or using the contentGetterCallback
254static const nbgl_content_t *getContentAtIdx(const nbgl_genericContents_t *genericContents,
255 int8_t contentIdx,
256 nbgl_content_t *content)
257{
258 nbgl_pageContent_t pageContent = {0};
259 if (contentIdx < 0 || contentIdx >= genericContents->nbContents) {
260 LOG_DEBUG(USE_CASE_LOGGER, "No content available at %d\n", contentIdx);
261 return NULL;
262 }
263
264 if (genericContents->callbackCallNeeded) {
265 if (content == NULL) {
266 LOG_DEBUG(USE_CASE_LOGGER, "Invalid content variable\n");
267 return NULL;
268 }
269 // Retrieve content through callback, but first memset the content.
270 memset(content, 0, sizeof(nbgl_content_t));
271 if (context.content.navCallback) {
272 if (context.content.navCallback(contentIdx, &pageContent) == true) {
273 // Copy the Page Content to the Content variable
274 content->type = pageContent.type;
275 switch (content->type) {
276 case CENTERED_INFO:
277 content->content.centeredInfo = pageContent.centeredInfo;
278 break;
279 case INFO_BUTTON:
280 content->content.infoButton = pageContent.infoButton;
281 break;
282 case TAG_VALUE_LIST:
283 content->content.tagValueList = pageContent.tagValueList;
284 break;
285 case SWITCHES_LIST:
286 content->content.switchesList = pageContent.switchesList;
287 break;
288 case INFOS_LIST:
289 content->content.infosList = pageContent.infosList;
290 break;
291 case CHOICES_LIST:
292 content->content.choicesList = pageContent.choicesList;
293 break;
294 case BARS_LIST:
295 content->content.barsList = pageContent.barsList;
296 break;
297 default:
298 LOG_DEBUG(USE_CASE_LOGGER, "Invalid content type\n");
299 return NULL;
300 }
301 }
302 else {
303 LOG_DEBUG(USE_CASE_LOGGER, "Error getting page content\n");
304 return NULL;
305 }
306 }
307 else {
308 genericContents->contentGetterCallback(contentIdx, content);
309 }
310 return content;
311 }
312 else {
313 // Retrieve content through list
314 return PIC(&genericContents->contentsList[contentIdx]);
315 }
316}
317
318// Helper to retrieve the content inside a nbgl_genericContents_t using
319// either the contentsList or using the contentGetterCallback
320static const nbgl_content_t *getContentElemAtIdx(uint8_t elemIdx,
321 uint8_t *elemContentIdx,
322 nbgl_content_t *content)
323{
324 const nbgl_genericContents_t *genericContents = NULL;
325 const nbgl_content_t *p_content = NULL;
326 uint8_t nbPages = 0;
327 uint8_t elemNbPages = 0;
328
329 switch (context.type) {
330 case SETTINGS_USE_CASE:
331 case HOME_USE_CASE:
332 case GENERIC_SETTINGS:
333 genericContents = context.home.settingContents;
334 break;
335 case CONTENT_USE_CASE:
336 case GENERIC_REVIEW_USE_CASE:
337 genericContents = &context.content.genericContents;
338 break;
339 default:
340 return NULL;
341 }
342 for (int i = 0; i < genericContents->nbContents; i++) {
343 p_content = getContentAtIdx(genericContents, i, content);
344 elemNbPages = getContentNbElement(p_content);
345 if (nbPages + elemNbPages > elemIdx) {
346 *elemContentIdx = context.currentPage - nbPages;
347 break;
348 }
349 nbPages += elemNbPages;
350 }
351
352 return p_content;
353}
354
355static const char *getChoiceName(uint8_t choiceIndex)
356{
357 uint8_t elemIdx;
358 uint8_t nbValues;
359 const nbgl_content_t *p_content = NULL;
360 nbgl_content_t content = {0};
361 nbgl_contentRadioChoice_t *contentChoices = NULL;
362 nbgl_contentBarsList_t *contentBars = NULL;
363 char **names = NULL;
364
365 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
366 if (p_content == NULL) {
367 return NULL;
368 }
369 switch (p_content->type) {
370 case CHOICES_LIST:
371 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
372 names = (char **) PIC(contentChoices->names);
373 nbValues = contentChoices->nbChoices;
374 break;
375 case BARS_LIST:
376 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
377 names = (char **) PIC(contentBars->barTexts);
378 nbValues = contentBars->nbBars;
379 break;
380 default:
381 // Not supported as vertical MenuList
382 return NULL;
383 }
384 if (choiceIndex >= nbValues) {
385 // Last item is always "Back" button
386 return "Back";
387 }
388 return (const char *) PIC(names[choiceIndex]);
389}
390
391static void onChoiceSelected(uint8_t choiceIndex)
392{
393 uint8_t elemIdx;
394 uint8_t token = 255;
395 const nbgl_content_t *p_content = NULL;
396 nbgl_content_t content = {0};
397 nbgl_contentRadioChoice_t *contentChoices = NULL;
398 nbgl_contentBarsList_t *contentBars = NULL;
399
400 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
401 if (p_content == NULL) {
402 return;
403 }
404 switch (p_content->type) {
405 case CHOICES_LIST:
406 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
407 if (choiceIndex < contentChoices->nbChoices) {
408 token = contentChoices->token;
409 }
410 break;
411 case BARS_LIST:
412 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
413 if (choiceIndex < contentBars->nbBars) {
414 token = contentBars->tokens[choiceIndex];
415 }
416 break;
417 default:
418 // Not supported as vertical MenuList
419 break;
420 }
421 if ((token != 255) && (context.content.controlsCallback != NULL)) {
422 context.content.controlsCallback(token, 0);
423 }
424 else if (context.content.quitCallback != NULL) {
425 context.content.quitCallback();
426 }
427}
428
429static void getPairData(const nbgl_contentTagValueList_t *tagValueList,
430 uint8_t index,
431 const char **item,
432 const char **value,
433 const nbgl_contentValueExt_t **extension,
434 const nbgl_icon_details_t **icon,
435 bool *isCenteredInfo)
436{
437 const nbgl_contentTagValue_t *pair;
438
439 if (tagValueList->pairs != NULL) {
440 pair = PIC(&tagValueList->pairs[index]);
441 }
442 else {
443 pair = PIC(tagValueList->callback(index));
444 }
445 *item = pair->item;
446 *value = pair->value;
447 if (pair->aliasValue) {
448 *extension = pair->extension;
449 }
450 else if (pair->centeredInfo) {
451 *isCenteredInfo = true;
452 *icon = pair->valueIcon;
453 }
454 else {
455 *extension = NULL;
456 }
457}
458
459static void onReviewAccept(void)
460{
461 if (context.review.onChoice) {
462 context.review.onChoice(true);
463 }
464}
465
466static void onReviewReject(void)
467{
468 if (context.review.onChoice) {
469 context.review.onChoice(false);
470 }
471}
472
473static void onChoiceAccept(void)
474{
475 if (context.choice.onChoice) {
476 context.choice.onChoice(true);
477 }
478}
479
480static void onChoiceReject(void)
481{
482 if (context.choice.onChoice) {
483 context.choice.onChoice(false);
484 }
485}
486
487static void onConfirmAccept(void)
488{
489 if (context.confirm.currentStep) {
490 nbgl_stepRelease(context.confirm.currentStep);
491 }
492 if (context.confirm.onConfirm) {
493 context.confirm.onConfirm();
494 }
495}
496
497static void onConfirmReject(void)
498{
499 if (context.confirm.currentStep) {
500 nbgl_stepRelease(context.confirm.currentStep);
502 nbgl_refresh();
503 }
504}
505
506static void onSwitchAction(void)
507{
508 const nbgl_contentSwitch_t *contentSwitch = NULL;
509 const nbgl_content_t *p_content = NULL;
510 nbgl_content_t content = {0};
511 uint8_t elemIdx;
512
513 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
514 if ((p_content == NULL) || (p_content->type != SWITCHES_LIST)) {
515 return;
516 }
517 contentSwitch
518 = &((const nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
519 switch (context.type) {
520 case SETTINGS_USE_CASE:
521 case HOME_USE_CASE:
522 case GENERIC_SETTINGS:
523 displaySettingsPage(FORWARD_DIRECTION, true);
524 break;
525 case CONTENT_USE_CASE:
526 case GENERIC_REVIEW_USE_CASE:
527 displayContent(FORWARD_DIRECTION, true);
528 break;
529 default:
530 break;
531 }
532 if (p_content->contentActionCallback != NULL) {
533 nbgl_contentActionCallback_t actionCallback = PIC(p_content->contentActionCallback);
534 actionCallback(contentSwitch->token,
535 (contentSwitch->initState == ON_STATE) ? OFF_STATE : ON_STATE,
536 context.currentPage);
537 }
538 else if (context.content.controlsCallback != NULL) {
539 context.content.controlsCallback(contentSwitch->token, 0);
540 }
541}
542
543static void drawStep(nbgl_stepPosition_t pos,
544 const nbgl_icon_details_t *icon,
545 const char *txt,
546 const char *subTxt,
547 nbgl_stepButtonCallback_t onActionCallback,
548 bool modal,
549 ForcedType_t forcedType)
550{
551 uint8_t elemIdx;
552 nbgl_step_t newStep = NULL;
553 const nbgl_content_t *p_content = NULL;
554 nbgl_content_t content = {0};
555 nbgl_contentRadioChoice_t *contentChoices = NULL;
556 nbgl_contentBarsList_t *contentBars = NULL;
557 nbgl_screenTickerConfiguration_t *p_ticker = NULL;
558 nbgl_layoutMenuList_t list = {0};
559 nbgl_screenTickerConfiguration_t ticker = {.tickerCallback = PIC(statusTickerCallback),
560 .tickerIntervale = 0, // not periodic
561 .tickerValue = STATUS_SCREEN_DURATION};
562
563 pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
564 // if we are in streaming+skip case, enable going backward even for first tag/value of the set
565 // (except the first set) because the set starts with a "skip" page
566 if ((context.type == STREAMING_CONTINUE_REVIEW_USE_CASE)
567 && (context.review.skipCallback != NULL) && (context.review.nbDataSets > 1)) {
568 pos |= LAST_STEP;
569 }
570 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
571 p_ticker = &ticker;
572 }
573 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
574 nbgl_stepRelease(context.confirm.currentStep);
575 }
576
577 if (txt == NULL) {
578 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
579 if (p_content) {
580 switch (p_content->type) {
581 case CHOICES_LIST:
582 contentChoices
583 = ((nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList));
584 list.nbChoices = contentChoices->nbChoices + 1; // For Back button
585 list.selectedChoice = contentChoices->initChoice;
586 list.callback = getChoiceName;
587 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
588 break;
589 case BARS_LIST:
590 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
591 list.nbChoices = contentBars->nbBars + 1; // For Back button
592 list.selectedChoice = 0;
593 list.callback = getChoiceName;
594 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
595 break;
596 default:
597 // Not supported as vertical MenuList
598 break;
599 }
600 }
601 }
602 else if ((icon == NULL) && (forcedType != FORCE_CENTERED_INFO)) {
604 if (subTxt != NULL) {
605 style = (forcedType == FORCE_BUTTON) ? BUTTON_INFO : BOLD_TEXT1_INFO;
606 }
607 else {
608 style = REGULAR_INFO;
609 }
610 newStep = nbgl_stepDrawText(pos, onActionCallback, p_ticker, txt, subTxt, style, modal);
611 }
612 else {
614 info.icon = icon;
615 info.text1 = txt;
616 info.text2 = subTxt;
617 info.onTop = false;
618 if ((subTxt != NULL) || (context.stepCallback != NULL)) {
619 info.style = BOLD_TEXT1_INFO;
620 }
621 else {
622 info.style = REGULAR_INFO;
623 }
624 newStep = nbgl_stepDrawCenteredInfo(pos, onActionCallback, p_ticker, &info, modal);
625 }
626 if (context.type == CONFIRM_USE_CASE) {
627 context.confirm.currentStep = newStep;
628 }
629}
630
631static void drawSwitchStep(nbgl_stepPosition_t pos,
632 const char *title,
633 const char *description,
634 bool state,
635 nbgl_stepButtonCallback_t onActionCallback,
636 bool modal)
637{
638 nbgl_layoutSwitch_t switchInfo;
639
640 pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
641 switchInfo.initState = state;
642 switchInfo.text = title;
643 switchInfo.subText = description;
644 nbgl_stepDrawSwitch(pos, onActionCallback, NULL, &switchInfo, modal);
645}
646
647static bool buttonGenericCallback(nbgl_buttonEvent_t event, nbgl_stepPosition_t *pos)
648{
649 uint8_t elemIdx;
650 uint8_t token = 0;
651 uint8_t index = 0;
652 const nbgl_content_t *p_content = NULL;
653 nbgl_content_t content = {0};
654
655 if (event == BUTTON_LEFT_PRESSED) {
656 if (context.currentPage > 0) {
657 context.currentPage--;
658 }
659 // in streaming+skip case, it is allowed to go backward at the first tag/value, except for
660 // the first set
661 else if ((context.type != STREAMING_CONTINUE_REVIEW_USE_CASE)
662 || (context.review.skipCallback == NULL) || (context.review.nbDataSets == 1)) {
663 // Drop the event
664 return false;
665 }
666 *pos = BACKWARD_DIRECTION;
667 }
668 else if (event == BUTTON_RIGHT_PRESSED) {
669 if (context.currentPage < (int) (context.nbPages - 1)) {
670 context.currentPage++;
671 }
672 else {
673 // Drop the event
674 return false;
675 }
676 *pos = FORWARD_DIRECTION;
677 }
678 else {
679 if (event == BUTTON_BOTH_PRESSED) {
680 if (context.stepCallback != NULL) {
681 context.stepCallback();
682 }
683 else if ((context.type == CONTENT_USE_CASE) || (context.type == SETTINGS_USE_CASE)
684 || (context.type == GENERIC_SETTINGS)
685 || (context.type == GENERIC_REVIEW_USE_CASE)) {
686 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
687 if (p_content != NULL) {
688 switch (p_content->type) {
689 case CENTERED_INFO:
690 // No associated callback
691 return false;
692 case INFO_BUTTON:
693 token = p_content->content.infoButton.buttonToken;
694 break;
695 case SWITCHES_LIST:
696 token = p_content->content.switchesList.switches->token;
697 break;
698 case BARS_LIST:
699 token = p_content->content.barsList.tokens[context.currentPage];
700 break;
701 case CHOICES_LIST:
702 token = p_content->content.choicesList.token;
703 index = context.currentPage;
704 break;
705 default:
706 break;
707 }
708
709 if ((p_content) && (p_content->contentActionCallback != NULL)) {
710 p_content->contentActionCallback(token, 0, context.currentPage);
711 }
712 else if (context.content.controlsCallback != NULL) {
713 context.content.controlsCallback(token, index);
714 }
715 }
716 }
717 }
718 return false;
719 }
720 return true;
721}
722
723static void reviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
724{
725 UNUSED(stepCtx);
727
728 if (!buttonGenericCallback(event, &pos)) {
729 return;
730 }
731
732 displayReviewPage(pos);
733}
734
735// this is the callback used when button action on the "skip" page
736static void buttonSkipCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
737{
738 UNUSED(stepCtx);
740
741 if (event == BUTTON_LEFT_PRESSED) {
742 // only decrement page if we are going backward but coming from forward (back & forth)
743 if ((context.review.dataDirection == FORWARD_DIRECTION) && (context.currentPage > 0)) {
744 context.currentPage--;
745 }
746 pos = BACKWARD_DIRECTION;
747 }
748 else if (event == BUTTON_RIGHT_PRESSED) {
749 // only increment page if we are going forward but coming from backward (back & forth)
750 if ((context.review.dataDirection == BACKWARD_DIRECTION)
751 && (context.currentPage < (int) (context.nbPages - 1)) && (context.currentPage > 0)) {
752 context.currentPage++;
753 }
754 pos = FORWARD_DIRECTION;
755 }
756 else if (event == BUTTON_BOTH_PRESSED) {
757 context.review.skipCallback();
758 return;
759 }
760 else {
761 return;
762 }
763 displayStreamingReviewPage(pos);
764}
765
766// this is the callback used when buttons in "Action" use case are pressed
767static void useCaseActionCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
768{
769 UNUSED(stepCtx);
770
771 if (event == BUTTON_BOTH_PRESSED) {
772 context.action.actionCallback();
773 }
774}
775
776static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
777{
779 UNUSED(stepCtx);
780
781 if (!buttonGenericCallback(event, &pos)) {
782 return;
783 }
784 else {
785 // memorize last direction
786 context.review.dataDirection = pos;
787 }
788
789 displayStreamingReviewPage(pos);
790}
791
792static void settingsCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
793{
794 UNUSED(stepCtx);
796
797 if (!buttonGenericCallback(event, &pos)) {
798 return;
799 }
800
801 displaySettingsPage(pos, false);
802}
803
804static void infoCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
805{
806 UNUSED(stepCtx);
808
809 if (!buttonGenericCallback(event, &pos)) {
810 return;
811 }
812
813 displayInfoPage(pos);
814}
815
816static void homeCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
817{
818 UNUSED(stepCtx);
820
821 if (!buttonGenericCallback(event, &pos)) {
822 return;
823 }
824
825 displayHomePage(pos);
826}
827
828static void genericChoiceCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
829{
830 UNUSED(stepCtx);
832
833 if (!buttonGenericCallback(event, &pos)) {
834 return;
835 }
836
837 displayChoicePage(pos);
838}
839
840static void genericConfirmCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
841{
842 UNUSED(stepCtx);
844
845 if (!buttonGenericCallback(event, &pos)) {
846 return;
847 }
848
849 displayConfirm(pos);
850}
851
852static void statusButtonCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
853{
854 UNUSED(stepCtx);
855 // any button press should dismiss the status screen
856 if ((event == BUTTON_BOTH_PRESSED) || (event == BUTTON_LEFT_PRESSED)
857 || (event == BUTTON_RIGHT_PRESSED)) {
858 if (context.stepCallback != NULL) {
859 context.stepCallback();
860 }
861 }
862}
863
864static void contentCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
865{
866 UNUSED(stepCtx);
868
869 if (!buttonGenericCallback(event, &pos)) {
870 return;
871 }
872
873 displayContent(pos, false);
874}
875
876// callback used for timeout
877static void statusTickerCallback(void)
878{
879 if (context.stepCallback != NULL) {
880 context.stepCallback();
881 }
882}
883
884// this is the callback used when navigating in extension pages
885static void extensionNavigate(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
886{
888 UNUSED(stepCtx);
889
890 if (event == BUTTON_LEFT_PRESSED) {
891 // only decrement page if we are not at the first page
892 if (context.review.currentExtensionPage > 0) {
893 context.review.currentExtensionPage--;
894 }
895 pos = BACKWARD_DIRECTION;
896 }
897 else if (event == BUTTON_RIGHT_PRESSED) {
898 // only increment page if not at last page
899 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
900 context.review.currentExtensionPage++;
901 }
902 pos = FORWARD_DIRECTION;
903 }
904 else if (event == BUTTON_BOTH_PRESSED) {
905 // if at last page, leave modal context
906 if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
907 nbgl_stepRelease(context.review.extensionStepCtx);
909 nbgl_refresh();
910 }
911 return;
912 }
913 else {
914 return;
915 }
916 displayExtensionStep(pos);
917}
918
919// function used to display the extension pages
920static void displayExtensionStep(nbgl_stepPosition_t pos)
921{
922 nbgl_layoutCenteredInfo_t info = {0};
923 const nbgl_contentTagValueList_t *tagValueList = NULL;
924 const nbgl_contentInfoList_t *infoList = NULL;
925 const char *text = NULL;
926 const char *subText = NULL;
927
928 if (context.review.extensionStepCtx != NULL) {
929 nbgl_stepRelease(context.review.extensionStepCtx);
930 }
931 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
932 if (context.review.currentExtensionPage == 0) {
933 pos |= FIRST_STEP;
934 }
935 else {
937 }
938
939 switch (context.review.extension->aliasType) {
940 case ENS_ALIAS:
941 text = context.review.extension->title;
942 subText = context.review.extension->fullValue;
943 break;
944 case INFO_LIST_ALIAS:
945 infoList = context.review.extension->infolist;
946 text = PIC(infoList->infoTypes[context.review.currentExtensionPage]);
947 subText = PIC(infoList->infoContents[context.review.currentExtensionPage]);
948 break;
950 tagValueList = context.review.extension->tagValuelist;
951 text = PIC(tagValueList->pairs[context.review.currentExtensionPage].item);
952 subText = PIC(tagValueList->pairs[context.review.currentExtensionPage].value);
953 break;
954 default:
955 break;
956 }
957 if (text != NULL) {
958 context.review.extensionStepCtx = nbgl_stepDrawText(
959 pos, extensionNavigate, NULL, text, subText, BOLD_TEXT1_INFO, true);
960 }
961 }
962 else if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
963 // draw the back page
964 info.icon = &C_icon_back_x;
965 info.text1 = "Back";
966 info.style = BOLD_TEXT1_INFO;
967 pos |= LAST_STEP;
968 context.review.extensionStepCtx
969 = nbgl_stepDrawCenteredInfo(pos, extensionNavigate, NULL, &info, true);
970 }
971 nbgl_refresh();
972}
973
974static void displayAliasFullValue(void)
975{
976 const char *text = NULL;
977 const char *subText = NULL;
978 const nbgl_icon_details_t *icon;
979 bool isCenteredInfo;
980
981 getPairData(context.review.tagValueList,
982 context.review.currentTagValueIndex,
983 &text,
984 &subText,
985 &context.review.extension,
986 &icon,
987 &isCenteredInfo);
988 if (context.review.extension == NULL) {
989 // probably an error
991 "displayAliasFullValue: extension nor found for pair %d\n",
992 context.review.currentTagValueIndex);
993 return;
994 }
995 context.review.currentExtensionPage = 0;
996 context.review.extensionStepCtx = NULL;
997 // create a modal flow to display this extension
998 switch (context.review.extension->aliasType) {
999 case ENS_ALIAS:
1000 context.review.nbExtensionPages = 2;
1001 break;
1002 case INFO_LIST_ALIAS:
1003 context.review.nbExtensionPages = context.review.extension->infolist->nbInfos + 1;
1004 break;
1006 context.review.nbExtensionPages = context.review.extension->tagValuelist->nbPairs + 1;
1007 break;
1008 default:
1010 "displayAliasFullValue: unsupported alias type %d\n",
1011 context.review.extension->aliasType);
1012 return;
1013 }
1014 displayExtensionStep(FORWARD_DIRECTION);
1015}
1016
1017static void getLastPageInfo(bool approve, const nbgl_icon_details_t **icon, const char **text)
1018{
1019 if (approve) {
1020 // Approve page
1021 *icon = &C_icon_validate_14;
1022 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1023 *text = "Confirm";
1024 }
1025 else {
1026 // if finish title is provided, use it
1027 if (context.review.finishTitle != NULL) {
1028 *text = context.review.finishTitle;
1029 }
1030 else {
1031 switch (context.operationType & REAL_TYPE_MASK) {
1032 case TYPE_TRANSACTION:
1033 if (context.operationType & RISKY_OPERATION) {
1034 *text = "Accept risk and sign transaction";
1035 }
1036 else {
1037 *text = "Sign transaction";
1038 }
1039 break;
1040 case TYPE_MESSAGE:
1041 if (context.operationType & RISKY_OPERATION) {
1042 *text = "Accept risk and sign message";
1043 }
1044 else {
1045 *text = "Sign message";
1046 }
1047 break;
1048 default:
1049 if (context.operationType & RISKY_OPERATION) {
1050 *text = "Accept risk and sign operation";
1051 }
1052 else {
1053 *text = "Sign operation";
1054 }
1055 break;
1056 }
1057 }
1058 }
1059 context.stepCallback = onReviewAccept;
1060 }
1061 else {
1062 // Reject page
1063 *icon = &C_icon_crossmark;
1064 if (context.type == ADDRESS_REVIEW_USE_CASE) {
1065 *text = "Cancel";
1066 }
1067 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_TRANSACTION) {
1068 *text = "Reject transaction";
1069 }
1070 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_MESSAGE) {
1071 *text = "Reject message";
1072 }
1073 else {
1074 *text = "Reject operation";
1075 }
1076 context.stepCallback = onReviewReject;
1077 }
1078}
1079
1080// function used to display the current page in review
1081static void displayReviewPage(nbgl_stepPosition_t pos)
1082{
1083 uint8_t reviewPages = 0;
1084 uint8_t finalPages = 0;
1085 uint8_t pairIndex = 0;
1086 const char *text = NULL;
1087 const char *subText = NULL;
1088 const nbgl_icon_details_t *icon = NULL;
1089 uint8_t currentIndex = 0;
1090 uint8_t titleIndex = 255;
1091 uint8_t subIndex = 255;
1092 uint8_t approveIndex = 255;
1093 uint8_t rejectIndex = 255;
1094 const nbgl_contentValueExt_t *extension = NULL;
1095 ForcedType_t forcedType = NO_FORCED_TYPE;
1096
1097 context.stepCallback = NULL;
1098
1099 // Determine the 1st page to display tag/values
1100 // Title page to display
1101 titleIndex = currentIndex++;
1102 reviewPages++;
1103 if (context.review.reviewSubTitle) {
1104 // subtitle page to display
1105 subIndex = currentIndex++;
1106 reviewPages++;
1107 }
1108 approveIndex = context.nbPages - 2;
1109 rejectIndex = context.nbPages - 1;
1110 finalPages = approveIndex;
1111
1112 // Determine which page to display
1113 if (context.currentPage >= finalPages) {
1114 if (context.currentPage == approveIndex) {
1115 // Approve page
1116 getLastPageInfo(true, &icon, &text);
1117 }
1118 else if (context.currentPage == rejectIndex) {
1119 // Reject page
1120 getLastPageInfo(false, &icon, &text);
1121 }
1122 }
1123 else if (context.currentPage < reviewPages) {
1124 if (context.currentPage == titleIndex) {
1125 // Title page
1126 icon = context.review.icon;
1127 text = context.review.reviewTitle;
1128 }
1129 else if (context.currentPage == subIndex) {
1130 // SubTitle page
1131 text = context.review.reviewSubTitle;
1132 }
1133 }
1134 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
1135 // address confirmation and 2nd page
1136 text = "Address";
1137 subText = context.review.address;
1138 }
1139 else {
1140 bool isCenteredInfo = false;
1141 pairIndex = context.currentPage - reviewPages;
1142 if (context.review.address != NULL) {
1143 pairIndex--;
1144 }
1145 getPairData(context.review.tagValueList,
1146 pairIndex,
1147 &text,
1148 &subText,
1149 &extension,
1150 &icon,
1151 &isCenteredInfo);
1152 if (extension != NULL) {
1153 context.stepCallback = displayAliasFullValue;
1154 context.review.currentTagValueIndex = pairIndex;
1155 forcedType = FORCE_BUTTON;
1156 }
1157 else {
1158 if (isCenteredInfo) {
1159 forcedType = FORCE_CENTERED_INFO;
1160 }
1161 }
1162 }
1163
1164 drawStep(pos, icon, text, subText, reviewCallback, false, forcedType);
1165 nbgl_refresh();
1166}
1167
1168// function used to display the current page in review
1169static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
1170{
1171 const char *text = NULL;
1172 const char *subText = NULL;
1173 const nbgl_icon_details_t *icon = NULL;
1174 uint8_t reviewPages = 0;
1175 uint8_t titleIndex = 255;
1176 uint8_t subIndex = 255;
1177 const nbgl_contentValueExt_t *extension = NULL;
1178 ForcedType_t forcedType = NO_FORCED_TYPE;
1179
1180 context.stepCallback = NULL;
1181 switch (context.type) {
1182 case STREAMING_START_REVIEW_USE_CASE:
1183 // Title page to display
1184 titleIndex = reviewPages++;
1185 if (context.review.reviewSubTitle) {
1186 // subtitle page to display
1187 subIndex = reviewPages++;
1188 }
1189 // Determine which page to display
1190 if (context.currentPage >= reviewPages) {
1191 onReviewAccept();
1192 return;
1193 }
1194 // header page(s)
1195 if (context.currentPage == titleIndex) {
1196 // title page
1197 icon = context.review.icon;
1198 text = context.review.reviewTitle;
1199 }
1200 else if (context.currentPage == subIndex) {
1201 // subtitle page
1202 text = context.review.reviewSubTitle;
1203 }
1204 break;
1205
1206 case STREAMING_CONTINUE_REVIEW_USE_CASE:
1207 if (context.currentPage >= context.review.tagValueList->nbPairs) {
1208 onReviewAccept();
1209 return;
1210 }
1211 // if there is a skip, and we are not already displaying the "skip" page
1212 // and we are not at the first tag/value of the first set of data (except if going
1213 // backward) then display the "skip" page
1214 if ((context.review.skipCallback != NULL) && (context.review.skipDisplay == false)
1215 && ((context.review.nbDataSets > 1) || (context.currentPage > 0)
1216 || (context.review.dataDirection == BACKWARD_DIRECTION))) {
1217 nbgl_stepPosition_t directions = (pos & BACKWARD_DIRECTION) | FIRST_STEP;
1218 nbgl_layoutCenteredInfo_t info = {0};
1219 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1220 directions |= LAST_STEP;
1221 }
1222 info.icon = &C_Information_circle_14px;
1223 info.text1 = "Press right button to continue message or \bpress both to skip\b";
1224 nbgl_stepDrawCenteredInfo(directions, buttonSkipCallback, NULL, &info, false);
1225 nbgl_refresh();
1226 context.review.skipDisplay = true;
1227 return;
1228 }
1229 context.review.skipDisplay = false;
1230 bool isCenteredInfo = false;
1231 getPairData(context.review.tagValueList,
1232 context.currentPage,
1233 &text,
1234 &subText,
1235 &extension,
1236 &icon,
1237 &isCenteredInfo);
1238 if (extension != NULL) {
1239 forcedType = FORCE_BUTTON;
1240 }
1241 else {
1242 if (isCenteredInfo) {
1243 forcedType = FORCE_CENTERED_INFO;
1244 }
1245 }
1246 break;
1247
1248 case STREAMING_FINISH_REVIEW_USE_CASE:
1249 default:
1250 if (context.currentPage == 0) {
1251 // accept page
1252 getLastPageInfo(true, &icon, &text);
1253 }
1254 else {
1255 // reject page
1256 getLastPageInfo(false, &icon, &text);
1257 }
1258 break;
1259 }
1260
1261 drawStep(pos, icon, text, subText, streamingReviewCallback, false, forcedType);
1262 nbgl_refresh();
1263}
1264
1265// function used to display the current page in info
1266static void displayInfoPage(nbgl_stepPosition_t pos)
1267{
1268 const char *text = NULL;
1269 const char *subText = NULL;
1270 const nbgl_icon_details_t *icon = NULL;
1271
1272 context.stepCallback = NULL;
1273
1274 if (context.currentPage < (context.nbPages - 1)) {
1275 text = PIC(
1276 ((const char *const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
1277 subText = PIC(
1278 ((const char *const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
1279 }
1280 else {
1281 icon = &C_icon_back_x;
1282 text = "Back";
1283 context.stepCallback = startUseCaseHome;
1284 }
1285
1286 drawStep(pos, icon, text, subText, infoCallback, false, FORCE_CENTERED_INFO);
1287 nbgl_refresh();
1288}
1289
1290// function used to get the current page content
1291static void getContentPage(bool toogle_state, PageContent_t *contentPage)
1292{
1293 uint8_t elemIdx = 0;
1294 const nbgl_content_t *p_content = NULL;
1295 nbgl_content_t content = {0};
1296 nbgl_contentSwitch_t *contentSwitch = NULL;
1297#ifdef WITH_HORIZONTAL_CHOICES_LIST
1298 nbgl_contentRadioChoice_t *contentChoices = NULL;
1299 char **names = NULL;
1300#endif
1301#ifdef WITH_HORIZONTAL_BARS_LIST
1302 nbgl_contentBarsList_t *contentBars = NULL;
1303 char **texts = NULL;
1304#endif
1305 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
1306 if (p_content == NULL) {
1307 return;
1308 }
1309 switch (p_content->type) {
1310 case CENTERED_INFO:
1311 contentPage->text = PIC(p_content->content.centeredInfo.text1);
1312 contentPage->subText = PIC(p_content->content.centeredInfo.text2);
1313 break;
1314 case INFO_BUTTON:
1315 contentPage->icon = PIC(p_content->content.infoButton.icon);
1316 contentPage->text = PIC(p_content->content.infoButton.text);
1317 contentPage->subText = PIC(p_content->content.infoButton.buttonText);
1318 break;
1319 case TAG_VALUE_LIST:
1320 getPairData(&p_content->content.tagValueList,
1321 elemIdx,
1322 &contentPage->text,
1323 &contentPage->subText,
1324 &contentPage->extension,
1325 &contentPage->icon,
1326 &contentPage->isCenteredInfo);
1327 break;
1328 case SWITCHES_LIST:
1329 contentPage->isSwitch = true;
1330 contentSwitch = &(
1331 (nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
1332 contentPage->text = contentSwitch->text;
1333 contentPage->state = contentSwitch->initState;
1334 if (toogle_state) {
1335 contentPage->state = (contentPage->state == ON_STATE) ? OFF_STATE : ON_STATE;
1336 }
1337 context.stepCallback = onSwitchAction;
1338 contentPage->subText = contentSwitch->subText;
1339 break;
1340 case INFOS_LIST:
1341 contentPage->text
1342 = ((const char *const *) PIC(p_content->content.infosList.infoTypes))[elemIdx];
1343 contentPage->subText
1344 = ((const char *const *) PIC(p_content->content.infosList.infoContents))[elemIdx];
1345 break;
1346 case CHOICES_LIST:
1347#ifdef WITH_HORIZONTAL_CHOICES_LIST
1348 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
1349 names = (char **) PIC(contentChoices->names);
1350 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1351 contentPage->text = PIC(context.content.title);
1352 contentPage->subText = (const char *) PIC(names[elemIdx]);
1353 }
1354 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1355 contentPage->text = PIC(context.home.appName);
1356 contentPage->subText = (const char *) PIC(names[elemIdx]);
1357 }
1358 else {
1359 contentPage->text = (const char *) PIC(names[elemIdx]);
1360 }
1361#endif
1362 break;
1363 case BARS_LIST:
1364#ifdef WITH_HORIZONTAL_BARS_LIST
1365 contentBars = (nbgl_contentBarsList_t *) PIC(&p_content->content.barsList);
1366 texts = (char **) PIC(contentBars->barTexts);
1367 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1368 contentPage->text = PIC(context.content.title);
1369 contentPage->subText = PIC(texts[elemIdx]);
1370 }
1371 else if ((context.type == GENERIC_SETTINGS) && (context.home.appName != NULL)) {
1372 contentPage->text = PIC(context.home.appName);
1373 contentPage->subText = PIC(texts[elemIdx]);
1374 }
1375 else {
1376 contentPage->text = PIC(texts[elemIdx]);
1377 }
1378#endif
1379 break;
1380 default:
1381 break;
1382 }
1383}
1384
1385// function used to display the current page in settings
1386static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state)
1387{
1388 PageContent_t contentPage = {0};
1389
1390 context.stepCallback = NULL;
1391
1392 if (context.currentPage < (context.nbPages - 1)) {
1393 getContentPage(toogle_state, &contentPage);
1394 }
1395 else { // last page is for quit
1396 contentPage.icon = &C_icon_back_x;
1397 contentPage.text = "Back";
1398 if (context.type == GENERIC_SETTINGS) {
1399 context.stepCallback = context.home.quitCallback;
1400 }
1401 else {
1402 context.stepCallback = startUseCaseHome;
1403 }
1404 }
1405
1406 if (contentPage.isSwitch) {
1407 drawSwitchStep(
1408 pos, contentPage.text, contentPage.subText, contentPage.state, settingsCallback, false);
1409 }
1410 else {
1411 drawStep(pos,
1412 contentPage.icon,
1413 contentPage.text,
1414 contentPage.subText,
1415 settingsCallback,
1416 false,
1417 NO_FORCED_TYPE);
1418 }
1419
1420 nbgl_refresh();
1421}
1422
1423static void startUseCaseHome(void)
1424{
1425 switch (context.type) {
1426 case SETTINGS_USE_CASE:
1427 // Settings page index
1428 context.currentPage = 1;
1429 if (context.home.homeAction) {
1430 // Action page is before Settings page
1431 context.currentPage++;
1432 }
1433 break;
1434 case INFO_USE_CASE:
1435 // Info page index
1436 context.currentPage = 1;
1437 if (context.home.homeAction) {
1438 // Action page is before Settings and Info pages
1439 context.currentPage++;
1440 }
1441 if (context.home.settingContents) {
1442 // Settings page is before Info pages
1443 context.currentPage++;
1444 }
1445 break;
1446 default:
1447 // Home page index
1448 context.currentPage = 0;
1449 break;
1450 }
1451
1452 context.type = HOME_USE_CASE;
1453 context.nbPages = 2; // Home + Quit
1454 if (context.home.settingContents) {
1455 context.nbPages++;
1456 }
1457 if (context.home.infosList) {
1458 context.nbPages++;
1459 }
1460 if (context.home.homeAction) {
1461 context.nbPages++;
1462 }
1463 displayHomePage(FORWARD_DIRECTION);
1464}
1465
1466static void startUseCaseInfo(void)
1467{
1468 context.type = INFO_USE_CASE;
1469 context.nbPages = context.home.infosList->nbInfos + 1; // For back screen
1470 context.currentPage = 0;
1471
1472 displayInfoPage(FORWARD_DIRECTION);
1473}
1474
1475static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1476{
1477 nbgl_content_t content = {0};
1478 const nbgl_content_t *p_content = NULL;
1479
1480 // if not coming from GENERIC_SETTINGS, force to SETTINGS_USE_CASE
1481 if (context.type != GENERIC_SETTINGS) {
1482 context.type = SETTINGS_USE_CASE;
1483 }
1484
1485 context.nbPages = 1; // For back screen
1486 for (int i = 0; i < context.home.settingContents->nbContents; i++) {
1487 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1488 context.nbPages += getContentNbElement(p_content);
1489 }
1490 context.currentPage = initSettingPage;
1491
1492 displaySettingsPage(FORWARD_DIRECTION, false);
1493}
1494
1495static void startUseCaseSettings(void)
1496{
1497 startUseCaseSettingsAtPage(0);
1498}
1499
1500static void startUseCaseContent(void)
1501{
1502 uint8_t contentIdx = 0;
1503 const nbgl_content_t *p_content = NULL;
1504 nbgl_content_t content = {0};
1505
1506 context.nbPages = 1; // Quit
1507
1508 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1509 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1510 context.nbPages += getContentNbElement(p_content);
1511 }
1512
1513 // Ensure currentPage is valid
1514 if (context.currentPage >= context.nbPages) {
1515 return;
1516 }
1517
1518 displayContent(FORWARD_DIRECTION, false);
1519}
1520
1521// function used to display the current page in home
1522static void displayHomePage(nbgl_stepPosition_t pos)
1523{
1524 const char *text = NULL;
1525 const char *subText = NULL;
1526 const nbgl_icon_details_t *icon = NULL;
1527 uint8_t currentIndex = 0;
1528 uint8_t homeIndex = 255;
1529 uint8_t actionIndex = 255;
1530 uint8_t settingsIndex = 255;
1531 uint8_t infoIndex = 255;
1532
1533 context.stepCallback = NULL;
1534
1535 // Determine which pages are present
1536 homeIndex = currentIndex++;
1537 if (context.home.homeAction) {
1538 actionIndex = currentIndex++;
1539 }
1540 if (context.home.settingContents) {
1541 settingsIndex = currentIndex++;
1542 }
1543 if (context.home.infosList) {
1544 infoIndex = currentIndex++;
1545 }
1546
1547 if (context.currentPage == homeIndex) {
1548 // Home page
1549 icon = context.home.appIcon;
1550 if (context.home.tagline != NULL) {
1551 text = context.home.tagline;
1552 }
1553 else {
1554 text = context.home.appName;
1555 subText = "app is ready";
1556 }
1557 }
1558 else if (context.currentPage == actionIndex) {
1559 // Action page
1560 icon = context.home.homeAction->icon;
1561 text = PIC(context.home.homeAction->text);
1562 context.stepCallback = context.home.homeAction->callback;
1563 }
1564 else if (context.currentPage == settingsIndex) {
1565 // Settings page
1566 icon = &C_icon_coggle;
1567 text = "App settings";
1568 context.stepCallback = startUseCaseSettings;
1569 }
1570 else if (context.currentPage == infoIndex) {
1571 // About page
1572 icon = &C_Information_circle_14px;
1573 text = "App info";
1574 context.stepCallback = startUseCaseInfo;
1575 }
1576 else {
1577 icon = &C_Quit_14px;
1578 text = "Quit app";
1579 context.stepCallback = context.home.quitCallback;
1580 }
1581
1582 drawStep(pos, icon, text, subText, homeCallback, false, NO_FORCED_TYPE);
1583 nbgl_refresh();
1584}
1585
1586// function used to display the current page in choice
1587static void displayChoicePage(nbgl_stepPosition_t pos)
1588{
1589 const char *text = NULL;
1590 const char *subText = NULL;
1591 const nbgl_icon_details_t *icon = NULL;
1592 // set to 1 if there is only one page for intro (if either icon or subMessage is NULL)
1593 uint8_t acceptPage = 0;
1594
1595 if (context.choice.message != NULL) {
1596 if ((context.choice.icon == NULL) || (context.choice.subMessage == NULL)) {
1597 acceptPage = 1;
1598 }
1599 else {
1600 acceptPage = 2;
1601 }
1602 }
1603 context.stepCallback = NULL;
1604
1605 if (context.currentPage < acceptPage) {
1606 if (context.currentPage == 0) { // title page
1607 text = context.choice.message;
1608 if (context.choice.icon != NULL) {
1609 icon = context.choice.icon;
1610 }
1611 else {
1612 subText = context.choice.subMessage;
1613 }
1614 }
1615 else if ((acceptPage == 2) && (context.currentPage == 1)) { // sub-title page
1616 // displayed only if there is both icon and submessage
1617 text = context.choice.message;
1618 subText = context.choice.subMessage;
1619 }
1620 }
1621 else if (context.currentPage == acceptPage) { // confirm page
1622 icon = &C_icon_validate_14;
1623 text = context.choice.confirmText;
1624 context.stepCallback = onChoiceAccept;
1625 }
1626 else if (context.currentPage == (acceptPage + 1)) { // cancel page
1627 icon = &C_icon_crossmark;
1628 text = context.choice.cancelText;
1629 context.stepCallback = onChoiceReject;
1630 }
1631 else if (context.choice.details != NULL) {
1632 // only the first level of details and BAR_LIST type are supported
1633 if (context.choice.details->type == BAR_LIST_WARNING) {
1634 text = context.choice.details->barList.texts[context.currentPage - (acceptPage + 2)];
1635 subText
1636 = context.choice.details->barList.subTexts[context.currentPage - (acceptPage + 2)];
1637 }
1638 }
1639
1640 drawStep(pos, icon, text, subText, genericChoiceCallback, false, NO_FORCED_TYPE);
1641 nbgl_refresh();
1642}
1643
1644// function used to display the Confirm page
1645static void displayConfirm(nbgl_stepPosition_t pos)
1646{
1647 const char *text = NULL;
1648 const char *subText = NULL;
1649 const nbgl_icon_details_t *icon = NULL;
1650
1651 context.stepCallback = NULL;
1652 switch (context.currentPage) {
1653 case 0:
1654 // title page
1655 text = context.confirm.message;
1656 subText = context.confirm.subMessage;
1657 break;
1658 case 1:
1659 // confirm page
1660 icon = &C_icon_validate_14;
1661 text = context.confirm.confirmText;
1662 context.stepCallback = onConfirmAccept;
1663 break;
1664 case 2:
1665 // cancel page
1666 icon = &C_icon_crossmark;
1667 text = context.confirm.cancelText;
1668 context.stepCallback = onConfirmReject;
1669 break;
1670 }
1671
1672 drawStep(pos, icon, text, subText, genericConfirmCallback, true, NO_FORCED_TYPE);
1673 nbgl_refresh();
1674}
1675
1676// function used to display the current navigable content
1677static void displayContent(nbgl_stepPosition_t pos, bool toogle_state)
1678{
1679 PageContent_t contentPage = {0};
1680 ForcedType_t forcedType = NO_FORCED_TYPE;
1681
1682 context.stepCallback = NULL;
1683
1684 if (context.currentPage < (context.nbPages - 1)) {
1685 getContentPage(toogle_state, &contentPage);
1686 if (contentPage.isCenteredInfo) {
1687 forcedType = FORCE_CENTERED_INFO;
1688 }
1689 }
1690 else { // last page is for quit
1691 if (context.content.rejectText) {
1692 contentPage.text = context.content.rejectText;
1693 }
1694 else {
1695 contentPage.text = "Back";
1696 }
1697 if (context.type == GENERIC_REVIEW_USE_CASE) {
1698 contentPage.icon = &C_icon_crossmark;
1699 }
1700 else {
1701 contentPage.icon = &C_icon_back_x;
1702 }
1703 context.stepCallback = context.content.quitCallback;
1704 }
1705
1706 if (contentPage.isSwitch) {
1707 drawSwitchStep(
1708 pos, contentPage.text, contentPage.subText, contentPage.state, contentCallback, false);
1709 }
1710 else {
1711 drawStep(pos,
1712 contentPage.icon,
1713 contentPage.text,
1714 contentPage.subText,
1715 contentCallback,
1716 false,
1717 forcedType);
1718 }
1719
1720 nbgl_refresh();
1721}
1722
1723static void displaySpinner(const char *text)
1724{
1725 drawStep(SINGLE_STEP, &C_icon_processing, text, NULL, NULL, false, false);
1726 nbgl_refresh();
1727}
1728
1729// function to factorize code for all simple reviews
1730static void useCaseReview(ContextType_t type,
1731 nbgl_operationType_t operationType,
1732 const nbgl_contentTagValueList_t *tagValueList,
1733 const nbgl_icon_details_t *icon,
1734 const char *reviewTitle,
1735 const char *reviewSubTitle,
1736 const char *finishTitle,
1737 nbgl_choiceCallback_t choiceCallback)
1738{
1739 memset(&context, 0, sizeof(UseCaseContext_t));
1740 context.type = type;
1741 context.operationType = operationType;
1742 context.review.tagValueList = tagValueList;
1743 context.review.reviewTitle = reviewTitle;
1744 context.review.reviewSubTitle = reviewSubTitle;
1745 context.review.finishTitle = finishTitle;
1746 context.review.icon = icon;
1747 context.review.onChoice = choiceCallback;
1748 context.currentPage = 0;
1749 // 1 page for title and 2 pages at the end for accept/reject
1750 context.nbPages = tagValueList->nbPairs + 3;
1751 if (reviewSubTitle) {
1752 context.nbPages++; // 1 page for subtitle page
1753 }
1754
1755 displayReviewPage(FORWARD_DIRECTION);
1756}
1757
1758#ifdef NBGL_KEYPAD
1759static void setPinCodeText(void)
1760{
1761 bool enableValidate = false;
1762 bool enableBackspace = true;
1763
1764 // pin can be validated when min digits is entered
1765 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
1766 // backspace is disabled when no digit is entered and back vallback is not provided
1767 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
1768 nbgl_layoutUpdateKeypadContent(context.keypad.layoutCtx,
1769 context.keypad.hidden,
1770 context.keypad.pinLen,
1771 (const char *) context.keypad.pinEntry);
1773 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
1774 nbgl_layoutDraw(context.keypad.layoutCtx);
1775 nbgl_refresh();
1776}
1777
1778// called when a key is touched on the keypad
1779static void keypadCallback(char touchedKey)
1780{
1781 switch (touchedKey) {
1782 case BACKSPACE_KEY:
1783 if (context.keypad.pinLen > 0) {
1784 context.keypad.pinLen--;
1785 context.keypad.pinEntry[context.keypad.pinLen] = 0;
1786 }
1787 else if (context.keypad.backCallback != NULL) {
1788 context.keypad.backCallback();
1789 break;
1790 }
1791 setPinCodeText();
1792 break;
1793
1794 case VALIDATE_KEY:
1795 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
1796 break;
1797
1798 default:
1799 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1800 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
1801 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
1802 context.keypad.pinLen++;
1803 }
1804 setPinCodeText();
1805 }
1806 break;
1807 }
1808}
1809
1810// called to create a keypad, with either hidden or visible digits
1811static void keypadGenericUseCase(const char *title,
1812 uint8_t minDigits,
1813 uint8_t maxDigits,
1814 bool shuffled,
1815 bool hidden,
1816 nbgl_pinValidCallback_t validatePinCallback,
1817 nbgl_callback_t backCallback)
1818{
1819 nbgl_layoutDescription_t layoutDescription = {0};
1820 int status = -1;
1821
1822 // reset the keypad context
1823 memset(&context, 0, sizeof(KeypadContext_t));
1824 context.type = KEYPAD_USE_CASE;
1825 context.currentPage = 0;
1826 context.nbPages = 1;
1827 context.keypad.validatePin = validatePinCallback;
1828 context.keypad.backCallback = backCallback;
1829 context.keypad.pinMinDigits = minDigits;
1830 context.keypad.pinMaxDigits = maxDigits;
1831 context.keypad.hidden = hidden;
1832 context.keypad.layoutCtx = nbgl_layoutGet(&layoutDescription);
1833
1834 // add keypad
1835 status = nbgl_layoutAddKeypad(context.keypad.layoutCtx, keypadCallback, title, shuffled);
1836 if (status < 0) {
1837 return;
1838 }
1839 context.keypad.keypadIndex = status;
1840 // add digits
1841 status = nbgl_layoutAddKeypadContent(context.keypad.layoutCtx, hidden, maxDigits, "");
1842 if (status < 0) {
1843 return;
1844 }
1845
1846 nbgl_layoutDraw(context.keypad.layoutCtx);
1847 if (context.keypad.backCallback != NULL) {
1848 // force backspace to be visible at first digit, to be used as quit
1849 nbgl_layoutUpdateKeypad(context.keypad.layoutCtx, context.keypad.keypadIndex, false, true);
1850 }
1851 nbgl_refresh();
1852}
1853#endif // NBGL_KEYPAD
1854
1855// this is the function called to start the actual review, from the initial warning pages
1856static void launchReviewAfterWarning(void)
1857{
1858 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
1859 useCaseReview(reviewWithWarnCtx.type,
1860 reviewWithWarnCtx.operationType,
1861 reviewWithWarnCtx.tagValueList,
1862 reviewWithWarnCtx.icon,
1863 reviewWithWarnCtx.reviewTitle,
1864 reviewWithWarnCtx.reviewSubTitle,
1865 reviewWithWarnCtx.finishTitle,
1866 reviewWithWarnCtx.choiceCallback);
1867 }
1868 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
1869 displayStreamingReviewPage(FORWARD_DIRECTION);
1870 }
1871}
1872
1873// this is the callback used when navigating in warning pages
1874static void warningNavigate(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
1875{
1876 UNUSED(stepCtx);
1877
1878 if (event == BUTTON_LEFT_PRESSED) {
1879 // only decrement page if we are not at the first page
1880 if (reviewWithWarnCtx.warningPage > 0) {
1881 reviewWithWarnCtx.warningPage--;
1882 }
1883 }
1884 else if (event == BUTTON_RIGHT_PRESSED) {
1885 // only increment page if not at last page
1886 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
1887 reviewWithWarnCtx.warningPage++;
1888 }
1889 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
1890 && (reviewWithWarnCtx.warning->info != NULL)) {
1891 launchReviewAfterWarning();
1892 return;
1893 }
1894 }
1895 else if ((event == BUTTON_BOTH_PRESSED)
1896 && (reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN))) {
1897 // if at first page, double press leads to start of review
1898 if (reviewWithWarnCtx.warningPage == 0) {
1899 launchReviewAfterWarning();
1900 }
1901 // if at last page, reject operation
1902 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1903 reviewWithWarnCtx.choiceCallback(false);
1904 }
1905 return;
1906 }
1907 else {
1908 return;
1909 }
1910 displayWarningStep();
1911}
1912
1913// function used to display the initial warning pages when starting a "review with warning"
1914static void displayWarningStep(void)
1915{
1916 nbgl_layoutCenteredInfo_t info = {0};
1917 nbgl_stepPosition_t pos = 0;
1918 if (reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN)) {
1919 if (reviewWithWarnCtx.warningPage == 0) {
1920 // draw the main warning page
1921 info.icon = &C_icon_warning;
1922 info.text1 = "Blind signing ahead";
1923 info.text2 = "To accept risk, press both buttons";
1925 }
1926 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1927 getLastPageInfo(false, &info.icon, &info.text1);
1929 }
1930 }
1931 else if ((reviewWithWarnCtx.warning->predefinedSet == 0)
1932 && (reviewWithWarnCtx.warning->info != NULL)) {
1933 if (reviewWithWarnCtx.warningPage == 0) {
1934 info.icon = reviewWithWarnCtx.warning->info->icon;
1935 info.text1 = reviewWithWarnCtx.warning->info->title;
1936 info.text2 = reviewWithWarnCtx.warning->info->description;
1938 }
1939 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1940 if (reviewWithWarnCtx.warning->introDetails->type == CENTERED_INFO_WARNING) {
1941 info.icon = reviewWithWarnCtx.warning->introDetails->centeredInfo.icon;
1942 info.text1 = reviewWithWarnCtx.warning->introDetails->centeredInfo.title;
1943 info.text2 = reviewWithWarnCtx.warning->introDetails->centeredInfo.description;
1945 }
1946 else {
1947 // not supported
1948 return;
1949 }
1950 }
1951 }
1952 else {
1953 // not supported
1954 return;
1955 }
1956 info.style = BOLD_TEXT1_INFO;
1957 nbgl_stepDrawCenteredInfo(pos, warningNavigate, NULL, &info, false);
1958 nbgl_refresh();
1959}
1960
1961// function used to display the initial warning page when starting a "review with warning"
1962static void displayInitialWarning(void)
1963{
1964 // draw the main warning page
1965 reviewWithWarnCtx.warningPage = 0;
1966 reviewWithWarnCtx.nbWarningPages = 2;
1967 displayWarningStep();
1968}
1969
1970/**********************
1971 * GLOBAL FUNCTIONS
1972 **********************/
1973
1985uint8_t nbgl_useCaseGetNbTagValuesInPage(uint8_t nbPairs,
1986 const nbgl_contentTagValueList_t *tagValueList,
1987 uint8_t startIndex,
1988 bool *requireSpecificDisplay)
1989{
1990 UNUSED(nbPairs);
1991 UNUSED(tagValueList);
1992 UNUSED(startIndex);
1993 *requireSpecificDisplay = true;
1994 return 1;
1995}
1996
2009uint8_t nbgl_useCaseGetNbTagValuesInPageExt(uint8_t nbPairs,
2010 const nbgl_contentTagValueList_t *tagValueList,
2011 uint8_t startIndex,
2012 bool isSkippable,
2013 bool *requireSpecificDisplay)
2014{
2015 UNUSED(nbPairs);
2016 UNUSED(tagValueList);
2017 UNUSED(startIndex);
2018 UNUSED(isSkippable);
2019 *requireSpecificDisplay = true;
2020 return 1;
2021}
2022
2031uint8_t nbgl_useCaseGetNbInfosInPage(uint8_t nbInfos,
2032 const nbgl_contentInfoList_t *infosList,
2033 uint8_t startIndex,
2034 bool withNav)
2035{
2036 UNUSED(nbInfos);
2037 UNUSED(infosList);
2038 UNUSED(startIndex);
2039 UNUSED(withNav);
2040 return 1;
2041}
2042
2051uint8_t nbgl_useCaseGetNbSwitchesInPage(uint8_t nbSwitches,
2052 const nbgl_contentSwitchesList_t *switchesList,
2053 uint8_t startIndex,
2054 bool withNav)
2055{
2056 UNUSED(nbSwitches);
2057 UNUSED(switchesList);
2058 UNUSED(startIndex);
2059 UNUSED(withNav);
2060 return 1;
2061}
2062
2071uint8_t nbgl_useCaseGetNbBarsInPage(uint8_t nbBars,
2072 const nbgl_contentBarsList_t *barsList,
2073 uint8_t startIndex,
2074 bool withNav)
2075{
2076 UNUSED(nbBars);
2077 UNUSED(barsList);
2078 UNUSED(startIndex);
2079 UNUSED(withNav);
2080 return 1;
2081}
2082
2091uint8_t nbgl_useCaseGetNbChoicesInPage(uint8_t nbChoices,
2092 const nbgl_contentRadioChoice_t *choicesList,
2093 uint8_t startIndex,
2094 bool withNav)
2095{
2096 UNUSED(nbChoices);
2097 UNUSED(choicesList);
2098 UNUSED(startIndex);
2099 UNUSED(withNav);
2100 return 1;
2101}
2102
2110{
2111 uint8_t nbPages = 0;
2112 uint8_t nbPairs = tagValueList->nbPairs;
2113 uint8_t nbPairsInPage;
2114 uint8_t i = 0;
2115 bool flag;
2116
2117 while (i < tagValueList->nbPairs) {
2118 // upper margin
2119 nbPairsInPage = nbgl_useCaseGetNbTagValuesInPageExt(nbPairs, tagValueList, i, false, &flag);
2120 i += nbPairsInPage;
2121 nbPairs -= nbPairsInPage;
2122 nbPages++;
2123 }
2124 return nbPages;
2125}
2126
2140void nbgl_useCaseNavigableContent(const char *title,
2141 uint8_t initPage,
2142 uint8_t nbPages,
2143 nbgl_callback_t quitCallback,
2144 nbgl_navCallback_t navCallback,
2145 nbgl_layoutTouchCallback_t controlsCallback)
2146{
2147 memset(&context, 0, sizeof(UseCaseContext_t));
2148 context.type = CONTENT_USE_CASE;
2149 context.currentPage = initPage;
2150 context.content.title = title;
2151 context.content.quitCallback = quitCallback;
2152 context.content.navCallback = navCallback;
2153 context.content.controlsCallback = controlsCallback;
2154 context.content.genericContents.callbackCallNeeded = true;
2155 context.content.genericContents.nbContents = nbPages;
2156
2157 startUseCaseContent();
2158}
2159
2174void nbgl_useCaseHomeAndSettings(const char *appName,
2175 const nbgl_icon_details_t *appIcon,
2176 const char *tagline,
2177 const uint8_t initSettingPage,
2178 const nbgl_genericContents_t *settingContents,
2179 const nbgl_contentInfoList_t *infosList,
2180 const nbgl_homeAction_t *action,
2181 nbgl_callback_t quitCallback)
2182{
2183 memset(&context, 0, sizeof(UseCaseContext_t));
2184 context.home.appName = appName;
2185 context.home.appIcon = appIcon;
2186 context.home.tagline = tagline;
2187 context.home.settingContents = PIC(settingContents);
2188 context.home.infosList = PIC(infosList);
2189 context.home.homeAction = action;
2190 context.home.quitCallback = quitCallback;
2191
2192 if ((initSettingPage != INIT_HOME_PAGE) && (settingContents != NULL)) {
2193 startUseCaseSettingsAtPage(initSettingPage);
2194 }
2195 else {
2196 startUseCaseHome();
2197 }
2198}
2199
2212void nbgl_useCaseGenericSettings(const char *appName,
2213 uint8_t initPage,
2214 const nbgl_genericContents_t *settingContents,
2215 const nbgl_contentInfoList_t *infosList,
2216 nbgl_callback_t quitCallback)
2217{
2218 memset(&context, 0, sizeof(UseCaseContext_t));
2219 context.type = GENERIC_SETTINGS;
2220 context.home.appName = appName;
2221 context.home.settingContents = PIC(settingContents);
2222 context.home.infosList = PIC(infosList);
2223 context.home.quitCallback = quitCallback;
2224
2225 startUseCaseSettingsAtPage(initPage);
2226}
2227
2239void nbgl_useCaseGenericConfiguration(const char *title,
2240 uint8_t initPage,
2241 const nbgl_genericContents_t *contents,
2242 nbgl_callback_t quitCallback)
2243{
2244 nbgl_useCaseGenericSettings(title, initPage, contents, NULL, quitCallback);
2245}
2246
2261void nbgl_useCaseReview(nbgl_operationType_t operationType,
2262 const nbgl_contentTagValueList_t *tagValueList,
2263 const nbgl_icon_details_t *icon,
2264 const char *reviewTitle,
2265 const char *reviewSubTitle,
2266 const char *finishTitle,
2267 nbgl_choiceCallback_t choiceCallback)
2268{
2269 useCaseReview(REVIEW_USE_CASE,
2270 operationType,
2271 tagValueList,
2272 icon,
2273 reviewTitle,
2274 reviewSubTitle,
2275 finishTitle,
2276 choiceCallback);
2277}
2278
2302 const nbgl_contentTagValueList_t *tagValueList,
2303 const nbgl_icon_details_t *icon,
2304 const char *reviewTitle,
2305 const char *reviewSubTitle,
2306 const char *finishTitle,
2307 const nbgl_tipBox_t *tipBox,
2308 const nbgl_warning_t *warning,
2309 nbgl_choiceCallback_t choiceCallback)
2310{
2311 UNUSED(tipBox);
2312 ContextType_t type = REVIEW_USE_CASE;
2313
2314 // if no warning at all, it's a simple review
2315 if ((warning == NULL)
2316 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2317 && (warning->reviewDetails == NULL))) {
2318 useCaseReview(type,
2319 operationType,
2320 tagValueList,
2321 icon,
2322 reviewTitle,
2323 reviewSubTitle,
2324 finishTitle,
2325 choiceCallback);
2326 return;
2327 }
2328 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2329 operationType |= NO_THREAT_OPERATION;
2330 }
2331 else {
2332 operationType |= RISKY_OPERATION;
2333 }
2334
2335 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2336 reviewWithWarnCtx.type = type;
2337 reviewWithWarnCtx.operationType = operationType;
2338 reviewWithWarnCtx.tagValueList = tagValueList;
2339 reviewWithWarnCtx.icon = icon;
2340 reviewWithWarnCtx.reviewTitle = reviewTitle;
2341 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2342 reviewWithWarnCtx.finishTitle = finishTitle;
2343 reviewWithWarnCtx.warning = warning;
2344 reviewWithWarnCtx.choiceCallback = choiceCallback;
2345
2346 // display the initial warning only of a risk/threat or blind signing
2347 if ((!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2348 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2349 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN)))
2350 && (warning->introDetails == NULL)) {
2351 useCaseReview(type,
2352 operationType,
2353 tagValueList,
2354 icon,
2355 reviewTitle,
2356 reviewSubTitle,
2357 finishTitle,
2358 choiceCallback);
2359 return;
2360 }
2361 displayInitialWarning();
2362}
2363
2384 const nbgl_contentTagValueList_t *tagValueList,
2385 const nbgl_icon_details_t *icon,
2386 const char *reviewTitle,
2387 const char *reviewSubTitle,
2388 const char *finishTitle,
2389 const nbgl_tipBox_t *dummy,
2390 nbgl_choiceCallback_t choiceCallback)
2391{
2392 nbgl_useCaseAdvancedReview(operationType,
2393 tagValueList,
2394 icon,
2395 reviewTitle,
2396 reviewSubTitle,
2397 finishTitle,
2398 dummy,
2399 &blindSigningWarning,
2400 choiceCallback);
2401}
2402
2418 const nbgl_contentTagValueList_t *tagValueList,
2419 const nbgl_icon_details_t *icon,
2420 const char *reviewTitle,
2421 const char *reviewSubTitle,
2422 const char *finishTitle,
2423 nbgl_choiceCallback_t choiceCallback)
2424{
2425 nbgl_useCaseReview(operationType,
2426 tagValueList,
2427 icon,
2428 reviewTitle,
2429 reviewSubTitle,
2430 finishTitle,
2431 choiceCallback);
2432}
2433
2450void nbgl_useCaseAddressReview(const char *address,
2451 const nbgl_contentTagValueList_t *additionalTagValueList,
2452 const nbgl_icon_details_t *icon,
2453 const char *reviewTitle,
2454 const char *reviewSubTitle,
2455 nbgl_choiceCallback_t choiceCallback)
2456{
2457 memset(&context, 0, sizeof(UseCaseContext_t));
2458 context.type = ADDRESS_REVIEW_USE_CASE;
2459 context.review.address = address;
2460 context.review.reviewTitle = reviewTitle;
2461 context.review.reviewSubTitle = reviewSubTitle;
2462 context.review.icon = icon;
2463 context.review.onChoice = choiceCallback;
2464 context.currentPage = 0;
2465 // + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
2466 // + 1 if sub Title
2467 context.nbPages = reviewSubTitle ? 5 : 4;
2468 if (additionalTagValueList) {
2469 context.review.tagValueList = PIC(additionalTagValueList);
2470 context.nbPages += additionalTagValueList->nbPairs;
2471 }
2472
2473 displayReviewPage(FORWARD_DIRECTION);
2474}
2475
2485 const char *rejectText,
2486 nbgl_callback_t rejectCallback)
2487{
2488 memset(&context, 0, sizeof(UseCaseContext_t));
2489 context.type = GENERIC_REVIEW_USE_CASE;
2490 context.content.rejectText = rejectText;
2491 context.content.quitCallback = rejectCallback;
2492 context.content.genericContents.nbContents = contents->nbContents;
2493 context.content.genericContents.callbackCallNeeded = contents->callbackCallNeeded;
2494 if (contents->callbackCallNeeded) {
2495 context.content.genericContents.contentGetterCallback = contents->contentGetterCallback;
2496 }
2497 else {
2498 context.content.genericContents.contentsList = PIC(contents->contentsList);
2499 }
2500
2501 startUseCaseContent();
2502}
2503
2512void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
2513{
2514 UNUSED(isSuccess);
2515 memset(&context, 0, sizeof(UseCaseContext_t));
2516 context.type = STATUS_USE_CASE;
2517 context.stepCallback = quitCallback;
2518 context.currentPage = 0;
2519 context.nbPages = 1;
2520
2522 NULL,
2523 message,
2524 NULL,
2525 statusButtonCallback,
2526 false,
2527 NO_FORCED_TYPE);
2528}
2529
2537 nbgl_callback_t quitCallback)
2538{
2539 const char *msg;
2540 bool isSuccess;
2541 switch (reviewStatusType) {
2543 msg = "Operation signed";
2544 isSuccess = true;
2545 break;
2547 msg = "Operation rejected";
2548 isSuccess = false;
2549 break;
2551 msg = "Transaction signed";
2552 isSuccess = true;
2553 break;
2555 msg = "Transaction rejected";
2556 isSuccess = false;
2557 break;
2559 msg = "Message signed";
2560 isSuccess = true;
2561 break;
2563 msg = "Message rejected";
2564 isSuccess = false;
2565 break;
2567 msg = "Address verified";
2568 isSuccess = true;
2569 break;
2571 msg = "Address verification cancelled";
2572 isSuccess = false;
2573 break;
2574 default:
2575 return;
2576 }
2577 nbgl_useCaseStatus(msg, isSuccess, quitCallback);
2578}
2579
2593 const nbgl_icon_details_t *icon,
2594 const char *reviewTitle,
2595 const char *reviewSubTitle,
2596 nbgl_choiceCallback_t choiceCallback)
2597{
2598 // memorize streaming operation type for future API calls
2599 streamingOpType = operationType;
2600
2601 memset(&context, 0, sizeof(UseCaseContext_t));
2602 context.type = STREAMING_START_REVIEW_USE_CASE;
2603 context.operationType = operationType;
2604 context.review.reviewTitle = reviewTitle;
2605 context.review.reviewSubTitle = reviewSubTitle;
2606 context.review.icon = icon;
2607 context.review.onChoice = choiceCallback;
2608 context.currentPage = 0;
2609 context.nbPages = reviewSubTitle ? 3 : 2; // Start page(s) + trick for review continue
2610
2611 displayStreamingReviewPage(FORWARD_DIRECTION);
2612}
2613
2628 const nbgl_icon_details_t *icon,
2629 const char *reviewTitle,
2630 const char *reviewSubTitle,
2631 nbgl_choiceCallback_t choiceCallback)
2632{
2634 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
2635}
2636
2653 const nbgl_icon_details_t *icon,
2654 const char *reviewTitle,
2655 const char *reviewSubTitle,
2656 const nbgl_warning_t *warning,
2657 nbgl_choiceCallback_t choiceCallback)
2658{
2659 memset(&context, 0, sizeof(UseCaseContext_t));
2660 context.type = STREAMING_START_REVIEW_USE_CASE;
2661 context.operationType = operationType;
2662 context.review.reviewTitle = reviewTitle;
2663 context.review.reviewSubTitle = reviewSubTitle;
2664 context.review.icon = icon;
2665 context.review.onChoice = choiceCallback;
2666 context.currentPage = 0;
2667 context.nbPages = reviewSubTitle ? 3 : 2; // Start page(s) + trick for review continue
2668
2669 // memorize streaming operation type for future API calls
2670 streamingOpType = operationType;
2671
2672 // if no warning at all, it's a simple review
2673 if ((warning == NULL)
2674 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2675 && (warning->reviewDetails == NULL))) {
2676 displayStreamingReviewPage(FORWARD_DIRECTION);
2677 return;
2678 }
2679 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2680 operationType |= NO_THREAT_OPERATION;
2681 }
2682 else {
2683 operationType |= RISKY_OPERATION;
2684 }
2685 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2686
2687 reviewWithWarnCtx.type = context.type;
2688 reviewWithWarnCtx.operationType = operationType;
2689 reviewWithWarnCtx.icon = icon;
2690 reviewWithWarnCtx.reviewTitle = reviewTitle;
2691 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2692 reviewWithWarnCtx.choiceCallback = choiceCallback;
2693 reviewWithWarnCtx.warning = warning;
2694
2695 // display the initial warning only of a risk/threat or blind signing
2696 if ((!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2697 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2698 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN)))
2699 && (warning->introDetails == NULL)) {
2700 displayStreamingReviewPage(FORWARD_DIRECTION);
2701 return;
2702 }
2703 displayInitialWarning();
2704}
2705
2720 nbgl_choiceCallback_t choiceCallback,
2721 nbgl_callback_t skipCallback)
2722{
2723 uint8_t curNbDataSets = context.review.nbDataSets;
2724
2725 memset(&context, 0, sizeof(UseCaseContext_t));
2726 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2727 context.operationType = streamingOpType;
2728 context.review.tagValueList = tagValueList;
2729 context.review.onChoice = choiceCallback;
2730 context.currentPage = 0;
2731 context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
2732 context.review.skipCallback = skipCallback;
2733 context.review.nbDataSets = curNbDataSets + 1;
2734
2735 displayStreamingReviewPage(FORWARD_DIRECTION);
2736}
2737
2749 nbgl_choiceCallback_t choiceCallback)
2750{
2751 nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL);
2752}
2753
2754void nbgl_useCaseReviewStreamingFinish(const char *finishTitle,
2755 nbgl_choiceCallback_t choiceCallback)
2756{
2757 memset(&context, 0, sizeof(UseCaseContext_t));
2758 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
2759 context.operationType = streamingOpType;
2760 context.review.onChoice = choiceCallback;
2761 context.review.finishTitle = finishTitle;
2762 context.currentPage = 0;
2763 context.nbPages = 2; // 2 pages at the end for accept/reject
2764
2765 displayStreamingReviewPage(FORWARD_DIRECTION);
2766}
2767
2773void nbgl_useCaseSpinner(const char *text)
2774{
2775 memset(&context, 0, sizeof(UseCaseContext_t));
2776 context.type = SPINNER_USE_CASE;
2777 context.currentPage = 0;
2778 context.nbPages = 1;
2779
2780 displaySpinner(text);
2781}
2782
2796 const char *message,
2797 const char *subMessage,
2798 const char *confirmText,
2799 const char *cancelText,
2800 nbgl_choiceCallback_t callback)
2801{
2803 icon, message, subMessage, confirmText, cancelText, NULL, callback);
2804};
2805
2821 const char *message,
2822 const char *subMessage,
2823 const char *confirmText,
2824 const char *cancelText,
2825 nbgl_genericDetails_t *details,
2826 nbgl_choiceCallback_t callback)
2827{
2828 memset(&context, 0, sizeof(UseCaseContext_t));
2829 context.type = CHOICE_USE_CASE;
2830 context.choice.icon = icon;
2831 context.choice.message = message;
2832 context.choice.subMessage = subMessage;
2833 context.choice.confirmText = confirmText;
2834 context.choice.cancelText = cancelText;
2835 context.choice.onChoice = callback;
2836 context.choice.details = details;
2837 context.currentPage = 0;
2838 context.nbPages = 2; // 2 pages for confirm/cancel
2839 if (message != NULL) {
2840 context.nbPages++;
2841 // if both icon and subMessage are non NULL, add a page
2842 if ((icon != NULL) && (subMessage != NULL)) {
2843 context.nbPages++;
2844 }
2845 }
2846 if (details != NULL) {
2847 // only the first level of details and BAR_LIST type are supported
2848 if (details->type == BAR_LIST_WARNING) {
2849 context.nbPages += details->barList.nbBars;
2850 }
2851 }
2852
2853 displayChoicePage(FORWARD_DIRECTION);
2854};
2855
2869void nbgl_useCaseConfirm(const char *message,
2870 const char *subMessage,
2871 const char *confirmText,
2872 const char *cancelText,
2873 nbgl_callback_t callback)
2874{
2875 memset(&context, 0, sizeof(UseCaseContext_t));
2876 context.type = CONFIRM_USE_CASE;
2877 context.confirm.message = message;
2878 context.confirm.subMessage = subMessage;
2879 context.confirm.confirmText = confirmText;
2880 context.confirm.cancelText = cancelText;
2881 context.confirm.onConfirm = callback;
2882 context.currentPage = 0;
2883 context.nbPages = 1 + 2; // 2 pages at the end for confirm/cancel
2884
2885 displayConfirm(FORWARD_DIRECTION);
2886}
2887
2898 const char *message,
2899 const char *actionText,
2900 nbgl_callback_t callback)
2901{
2902 nbgl_layoutCenteredInfo_t centeredInfo = {0};
2903
2904 UNUSED(actionText);
2905
2906 // memorize callback in context
2907 memset(&context, 0, sizeof(UseCaseContext_t));
2908 context.type = ACTION_USE_CASE;
2909 context.action.actionCallback = callback;
2910
2911 centeredInfo.icon = icon;
2912 centeredInfo.text1 = message;
2913 centeredInfo.style = BOLD_TEXT1_INFO;
2914 nbgl_stepDrawCenteredInfo(0, useCaseActionCallback, NULL, &centeredInfo, false);
2915}
2916
2917#ifdef NBGL_KEYPAD
2935void nbgl_useCaseKeypadDigits(const char *title,
2936 uint8_t minDigits,
2937 uint8_t maxDigits,
2938 bool shuffled,
2939 nbgl_pinValidCallback_t validatePinCallback,
2940 nbgl_callback_t backCallback)
2941{
2942 keypadGenericUseCase(
2943 title, minDigits, maxDigits, shuffled, false, validatePinCallback, backCallback);
2944}
2945
2964void nbgl_useCaseKeypadPIN(const char *title,
2965 uint8_t minDigits,
2966 uint8_t maxDigits,
2967 bool shuffled,
2968 nbgl_pinValidCallback_t validatePinCallback,
2969 nbgl_callback_t backCallback)
2970{
2971 keypadGenericUseCase(
2972 title, minDigits, maxDigits, shuffled, true, validatePinCallback, backCallback);
2973}
2974#endif // NBGL_KEYPAD
2975
2976#endif // HAVE_SE_TOUCH
2977#endif // NBGL_USE_CASE
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_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
@ TAG_VALUE_LIST_ALIAS
@ 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
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
@ USE_CASE_LOGGER
Definition nbgl_debug.h:35
void(* nbgl_stepCallback_t)(void)
prototype of function to be called when a step is using a callback on "double-key" action
Definition nbgl_flow.h:38
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
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_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
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
void nbgl_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
Definition nbgl_obj.c:1705
nbgl_buttonEvent_t
Definition nbgl_obj.h:307
@ BUTTON_BOTH_PRESSED
Sent when both buttons are released.
Definition nbgl_obj.h:314
@ BUTTON_LEFT_PRESSED
Sent when Left button is released.
Definition nbgl_obj.h:308
@ BUTTON_RIGHT_PRESSED
Send when Right button is released.
Definition nbgl_obj.h:309
#define BACKSPACE_KEY
Definition nbgl_obj.h:26
#define VALIDATE_KEY
Definition nbgl_obj.h:27
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screenRedraw(void)
This function redraws the whole screen on top of stack and its children.
Definition nbgl_screen.c:66
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
Definition nbgl_step.h:57
#define GET_POS_OF_STEP(_step, _nb_steps)
Definition nbgl_step.h:30
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
Definition nbgl_step.h:44
uint8_t nbgl_stepPosition_t
this type is a bitfield containing:
Definition nbgl_step.h:88
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.
Definition nbgl_step.h:75
@ NEITHER_FIRST_NOR_LAST_STEP
neither first nor last in a multiple steps flow
Definition nbgl_step.h:67
@ SINGLE_STEP
single step flow
Definition nbgl_step.h:64
@ LAST_STEP
last in a multiple steps flow
Definition nbgl_step.h:66
@ FIRST_STEP
first in a multiple steps flow
Definition nbgl_step.h:65
int nbgl_stepRelease(nbgl_step_t step)
#define FORWARD_DIRECTION
When the flow is navigated from last to first step.
Definition nbgl_step.h:71
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.
Definition nbgl_step.h:73
nbgl_state_t
to represent a boolean state.
Definition nbgl_types.h:199
@ ON_STATE
Definition nbgl_types.h:201
@ OFF_STATE
Definition nbgl_types.h:200
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
void nbgl_useCaseGenericSettings(const char *appName, uint8_t initPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, nbgl_callback_t quitCallback)
void nbgl_useCaseKeypadPIN(const char *title, uint8_t minDigits, uint8_t maxDigits, uint8_t backToken, bool shuffled, tune_index_e tuneId, nbgl_pinValidCallback_t validatePinCallback, nbgl_layoutTouchCallback_t actionCallback)
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_useCaseKeypadDigits(const char *title, uint8_t minDigits, uint8_t maxDigits, uint8_t backToken, bool shuffled, tune_index_e tuneId, nbgl_pinValidCallback_t validatePinCallback, nbgl_layoutTouchCallback_t actionCallback)
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
@ W3C_THREAT_DETECTED_WARN
Web3 Checks: Threat detected (see reportRisk field)
@ BLIND_SIGNING_WARN
Blind signing.
@ W3C_NO_THREAT_WARN
Web3 Checks: No Threat detected.
@ W3C_RISK_DETECTED_WARN
Web3 Checks: Risk detected (see reportRisk field)
void nbgl_useCaseGenericConfiguration(const char *title, uint8_t initPage, const nbgl_genericContents_t *contents, nbgl_callback_t quitCallback)
#define INIT_HOME_PAGE
Value to pass to nbgl_useCaseHomeAndSettings() initSettingPage parameter to initialize the use case o...
void nbgl_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_useCaseReviewStreamingBlindSigningStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewLight(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
uint8_t nbgl_useCaseGetNbChoicesInPage(uint8_t nbChoices, const nbgl_contentRadioChoice_t *choicesList, uint8_t startIndex, bool withNav)
#define REAL_TYPE_MASK
This is the mask to apply on nbgl_operationType_t to get the real type provided by app.
void nbgl_useCaseReviewStatus(nbgl_reviewStatusType_t reviewStatusType, nbgl_callback_t quitCallback)
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
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_MESSAGE
@ 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)
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_content_u 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.
Structure containing all information when creating a layout. This structure must be passed as argumen...
This structure contains a list of names to build a menu list on Nanos, with for each item a descripti...
nbgl_menuListCallback_t callback
function to call to retrieve a menu list item text
uint8_t nbChoices
total number of choices in the menu list
uint8_t selectedChoice
index of the selected choice (centered, in bold)
This structure contains data to build a page in multi-pages mode (nbgl_pageDrawGenericContent)
Definition nbgl_flow.h:58
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type
Definition nbgl_flow.h:66
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
Definition nbgl_flow.h:64
nbgl_contentBarsList_t barsList
BARS_LIST type
Definition nbgl_flow.h:67
nbgl_contentInfoButton_t infoButton
INFO_BUTTON type
Definition nbgl_flow.h:62
nbgl_contentInfoList_t infosList
INFOS_LIST type
Definition nbgl_flow.h:65
nbgl_contentTagValueList_t tagValueList
TAG_VALUE_LIST type
Definition nbgl_flow.h:63
nbgl_contentType_t type
type of page content in the following union
Definition nbgl_flow.h:59
nbgl_contentCenteredInfo_t centeredInfo
CENTERED_INFO type
Definition nbgl_flow.h:61
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_warningDetails_t * introDetails
const nbgl_warningDetails_t * reviewDetails
uint32_t predefinedSet
nbgl_contentInfoList_t infosList
INFOS_LIST 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