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 callback used when navigating in warning pages
1856static void warningNavigate(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
1857{
1858 UNUSED(stepCtx);
1859
1860 if (event == BUTTON_LEFT_PRESSED) {
1861 // only decrement page if we are not at the first page
1862 if (reviewWithWarnCtx.warningPage > 0) {
1863 reviewWithWarnCtx.warningPage--;
1864 }
1865 }
1866 else if (event == BUTTON_RIGHT_PRESSED) {
1867 // only increment page if not at last page
1868 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
1869 reviewWithWarnCtx.warningPage++;
1870 }
1871 }
1872 else if (event == BUTTON_BOTH_PRESSED) {
1873 // if at first page, double press leads to start of review
1874 if (reviewWithWarnCtx.warningPage == 0) {
1875 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
1876 useCaseReview(reviewWithWarnCtx.type,
1877 reviewWithWarnCtx.operationType,
1878 reviewWithWarnCtx.tagValueList,
1879 reviewWithWarnCtx.icon,
1880 reviewWithWarnCtx.reviewTitle,
1881 reviewWithWarnCtx.reviewSubTitle,
1882 reviewWithWarnCtx.finishTitle,
1883 reviewWithWarnCtx.choiceCallback);
1884 }
1885 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
1886 displayStreamingReviewPage(FORWARD_DIRECTION);
1887 }
1888 }
1889 // if at last page, reject operation
1890 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1891 reviewWithWarnCtx.choiceCallback(false);
1892 }
1893 return;
1894 }
1895 else {
1896 return;
1897 }
1898 displayWarningStep();
1899}
1900
1901// function used to display the initial warning page when starting a "review with warning"
1902static void displayWarningStep(void)
1903{
1904 nbgl_layoutCenteredInfo_t info = {0};
1905 nbgl_stepPosition_t pos = 0;
1906 if (reviewWithWarnCtx.warningPage == 0) {
1907 // draw the main warning page
1908 info.icon = &C_icon_warning;
1909 info.text1 = "Blind signing ahead";
1910 info.text2 = "To accept risk, press both buttons";
1912 }
1913 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1914 getLastPageInfo(false, &info.icon, &info.text1);
1916 }
1917 info.style = BOLD_TEXT1_INFO;
1918 nbgl_stepDrawCenteredInfo(pos, warningNavigate, NULL, &info, false);
1919 nbgl_refresh();
1920}
1921
1922// function used to display the initial warning page when starting a "review with warning"
1923static void displayInitialWarning(void)
1924{
1925 // draw the main warning page
1926 reviewWithWarnCtx.warningPage = 0;
1927 reviewWithWarnCtx.nbWarningPages = 2;
1928 displayWarningStep();
1929}
1930
1931/**********************
1932 * GLOBAL FUNCTIONS
1933 **********************/
1934
1946uint8_t nbgl_useCaseGetNbTagValuesInPage(uint8_t nbPairs,
1947 const nbgl_contentTagValueList_t *tagValueList,
1948 uint8_t startIndex,
1949 bool *requireSpecificDisplay)
1950{
1951 UNUSED(nbPairs);
1952 UNUSED(tagValueList);
1953 UNUSED(startIndex);
1954 *requireSpecificDisplay = true;
1955 return 1;
1956}
1957
1970uint8_t nbgl_useCaseGetNbTagValuesInPageExt(uint8_t nbPairs,
1971 const nbgl_contentTagValueList_t *tagValueList,
1972 uint8_t startIndex,
1973 bool isSkippable,
1974 bool *requireSpecificDisplay)
1975{
1976 UNUSED(nbPairs);
1977 UNUSED(tagValueList);
1978 UNUSED(startIndex);
1979 UNUSED(isSkippable);
1980 *requireSpecificDisplay = true;
1981 return 1;
1982}
1983
1992uint8_t nbgl_useCaseGetNbInfosInPage(uint8_t nbInfos,
1993 const nbgl_contentInfoList_t *infosList,
1994 uint8_t startIndex,
1995 bool withNav)
1996{
1997 UNUSED(nbInfos);
1998 UNUSED(infosList);
1999 UNUSED(startIndex);
2000 UNUSED(withNav);
2001 return 1;
2002}
2003
2012uint8_t nbgl_useCaseGetNbSwitchesInPage(uint8_t nbSwitches,
2013 const nbgl_contentSwitchesList_t *switchesList,
2014 uint8_t startIndex,
2015 bool withNav)
2016{
2017 UNUSED(nbSwitches);
2018 UNUSED(switchesList);
2019 UNUSED(startIndex);
2020 UNUSED(withNav);
2021 return 1;
2022}
2023
2032uint8_t nbgl_useCaseGetNbBarsInPage(uint8_t nbBars,
2033 const nbgl_contentBarsList_t *barsList,
2034 uint8_t startIndex,
2035 bool withNav)
2036{
2037 UNUSED(nbBars);
2038 UNUSED(barsList);
2039 UNUSED(startIndex);
2040 UNUSED(withNav);
2041 return 1;
2042}
2043
2052uint8_t nbgl_useCaseGetNbChoicesInPage(uint8_t nbChoices,
2053 const nbgl_contentRadioChoice_t *choicesList,
2054 uint8_t startIndex,
2055 bool withNav)
2056{
2057 UNUSED(nbChoices);
2058 UNUSED(choicesList);
2059 UNUSED(startIndex);
2060 UNUSED(withNav);
2061 return 1;
2062}
2063
2071{
2072 uint8_t nbPages = 0;
2073 uint8_t nbPairs = tagValueList->nbPairs;
2074 uint8_t nbPairsInPage;
2075 uint8_t i = 0;
2076 bool flag;
2077
2078 while (i < tagValueList->nbPairs) {
2079 // upper margin
2080 nbPairsInPage = nbgl_useCaseGetNbTagValuesInPageExt(nbPairs, tagValueList, i, false, &flag);
2081 i += nbPairsInPage;
2082 nbPairs -= nbPairsInPage;
2083 nbPages++;
2084 }
2085 return nbPages;
2086}
2087
2101void nbgl_useCaseNavigableContent(const char *title,
2102 uint8_t initPage,
2103 uint8_t nbPages,
2104 nbgl_callback_t quitCallback,
2105 nbgl_navCallback_t navCallback,
2106 nbgl_layoutTouchCallback_t controlsCallback)
2107{
2108 memset(&context, 0, sizeof(UseCaseContext_t));
2109 context.type = CONTENT_USE_CASE;
2110 context.currentPage = initPage;
2111 context.content.title = title;
2112 context.content.quitCallback = quitCallback;
2113 context.content.navCallback = navCallback;
2114 context.content.controlsCallback = controlsCallback;
2115 context.content.genericContents.callbackCallNeeded = true;
2116 context.content.genericContents.nbContents = nbPages;
2117
2118 startUseCaseContent();
2119}
2120
2135void nbgl_useCaseHomeAndSettings(const char *appName,
2136 const nbgl_icon_details_t *appIcon,
2137 const char *tagline,
2138 const uint8_t initSettingPage,
2139 const nbgl_genericContents_t *settingContents,
2140 const nbgl_contentInfoList_t *infosList,
2141 const nbgl_homeAction_t *action,
2142 nbgl_callback_t quitCallback)
2143{
2144 memset(&context, 0, sizeof(UseCaseContext_t));
2145 context.home.appName = appName;
2146 context.home.appIcon = appIcon;
2147 context.home.tagline = tagline;
2148 context.home.settingContents = PIC(settingContents);
2149 context.home.infosList = PIC(infosList);
2150 context.home.homeAction = action;
2151 context.home.quitCallback = quitCallback;
2152
2153 if ((initSettingPage != INIT_HOME_PAGE) && (settingContents != NULL)) {
2154 startUseCaseSettingsAtPage(initSettingPage);
2155 }
2156 else {
2157 startUseCaseHome();
2158 }
2159}
2160
2173void nbgl_useCaseGenericSettings(const char *appName,
2174 uint8_t initPage,
2175 const nbgl_genericContents_t *settingContents,
2176 const nbgl_contentInfoList_t *infosList,
2177 nbgl_callback_t quitCallback)
2178{
2179 memset(&context, 0, sizeof(UseCaseContext_t));
2180 context.type = GENERIC_SETTINGS;
2181 context.home.appName = appName;
2182 context.home.settingContents = PIC(settingContents);
2183 context.home.infosList = PIC(infosList);
2184 context.home.quitCallback = quitCallback;
2185
2186 startUseCaseSettingsAtPage(initPage);
2187}
2188
2200void nbgl_useCaseGenericConfiguration(const char *title,
2201 uint8_t initPage,
2202 const nbgl_genericContents_t *contents,
2203 nbgl_callback_t quitCallback)
2204{
2205 nbgl_useCaseGenericSettings(title, initPage, contents, NULL, quitCallback);
2206}
2207
2222void nbgl_useCaseReview(nbgl_operationType_t operationType,
2223 const nbgl_contentTagValueList_t *tagValueList,
2224 const nbgl_icon_details_t *icon,
2225 const char *reviewTitle,
2226 const char *reviewSubTitle,
2227 const char *finishTitle,
2228 nbgl_choiceCallback_t choiceCallback)
2229{
2230 useCaseReview(REVIEW_USE_CASE,
2231 operationType,
2232 tagValueList,
2233 icon,
2234 reviewTitle,
2235 reviewSubTitle,
2236 finishTitle,
2237 choiceCallback);
2238}
2239
2263 const nbgl_contentTagValueList_t *tagValueList,
2264 const nbgl_icon_details_t *icon,
2265 const char *reviewTitle,
2266 const char *reviewSubTitle,
2267 const char *finishTitle,
2268 const nbgl_tipBox_t *tipBox,
2269 const nbgl_warning_t *warning,
2270 nbgl_choiceCallback_t choiceCallback)
2271{
2272 UNUSED(tipBox);
2273 ContextType_t type = REVIEW_USE_CASE;
2274
2275 // if no warning at all, it's a simple review
2276 if ((warning == NULL)
2277 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2278 && (warning->reviewDetails == NULL))) {
2279 useCaseReview(type,
2280 operationType,
2281 tagValueList,
2282 icon,
2283 reviewTitle,
2284 reviewSubTitle,
2285 finishTitle,
2286 choiceCallback);
2287 return;
2288 }
2289 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2290 operationType |= NO_THREAT_OPERATION;
2291 }
2292 else {
2293 operationType |= RISKY_OPERATION;
2294 }
2295
2296 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2297 reviewWithWarnCtx.type = type;
2298 reviewWithWarnCtx.operationType = operationType;
2299 reviewWithWarnCtx.tagValueList = tagValueList;
2300 reviewWithWarnCtx.icon = icon;
2301 reviewWithWarnCtx.reviewTitle = reviewTitle;
2302 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2303 reviewWithWarnCtx.finishTitle = finishTitle;
2304 reviewWithWarnCtx.warning = warning;
2305 reviewWithWarnCtx.choiceCallback = choiceCallback;
2306
2307 // display the initial warning only of a risk/threat or blind signing
2308 if (!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2309 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2310 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN))) {
2311 useCaseReview(type,
2312 operationType,
2313 tagValueList,
2314 icon,
2315 reviewTitle,
2316 reviewSubTitle,
2317 finishTitle,
2318 choiceCallback);
2319 return;
2320 }
2321 displayInitialWarning();
2322}
2323
2344 const nbgl_contentTagValueList_t *tagValueList,
2345 const nbgl_icon_details_t *icon,
2346 const char *reviewTitle,
2347 const char *reviewSubTitle,
2348 const char *finishTitle,
2349 const nbgl_tipBox_t *dummy,
2350 nbgl_choiceCallback_t choiceCallback)
2351{
2352 nbgl_useCaseAdvancedReview(operationType,
2353 tagValueList,
2354 icon,
2355 reviewTitle,
2356 reviewSubTitle,
2357 finishTitle,
2358 dummy,
2359 &blindSigningWarning,
2360 choiceCallback);
2361}
2362
2378 const nbgl_contentTagValueList_t *tagValueList,
2379 const nbgl_icon_details_t *icon,
2380 const char *reviewTitle,
2381 const char *reviewSubTitle,
2382 const char *finishTitle,
2383 nbgl_choiceCallback_t choiceCallback)
2384{
2385 nbgl_useCaseReview(operationType,
2386 tagValueList,
2387 icon,
2388 reviewTitle,
2389 reviewSubTitle,
2390 finishTitle,
2391 choiceCallback);
2392}
2393
2410void nbgl_useCaseAddressReview(const char *address,
2411 const nbgl_contentTagValueList_t *additionalTagValueList,
2412 const nbgl_icon_details_t *icon,
2413 const char *reviewTitle,
2414 const char *reviewSubTitle,
2415 nbgl_choiceCallback_t choiceCallback)
2416{
2417 memset(&context, 0, sizeof(UseCaseContext_t));
2418 context.type = ADDRESS_REVIEW_USE_CASE;
2419 context.review.address = address;
2420 context.review.reviewTitle = reviewTitle;
2421 context.review.reviewSubTitle = reviewSubTitle;
2422 context.review.icon = icon;
2423 context.review.onChoice = choiceCallback;
2424 context.currentPage = 0;
2425 // + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
2426 context.nbPages = 4;
2427 if (additionalTagValueList) {
2428 context.review.tagValueList = PIC(additionalTagValueList);
2429 context.nbPages += additionalTagValueList->nbPairs;
2430 }
2431
2432 displayReviewPage(FORWARD_DIRECTION);
2433}
2434
2444 const char *rejectText,
2445 nbgl_callback_t rejectCallback)
2446{
2447 memset(&context, 0, sizeof(UseCaseContext_t));
2448 context.type = GENERIC_REVIEW_USE_CASE;
2449 context.content.rejectText = rejectText;
2450 context.content.quitCallback = rejectCallback;
2451 context.content.genericContents.nbContents = contents->nbContents;
2452 context.content.genericContents.callbackCallNeeded = contents->callbackCallNeeded;
2453 if (contents->callbackCallNeeded) {
2454 context.content.genericContents.contentGetterCallback = contents->contentGetterCallback;
2455 }
2456 else {
2457 context.content.genericContents.contentsList = PIC(contents->contentsList);
2458 }
2459
2460 startUseCaseContent();
2461}
2462
2471void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
2472{
2473 UNUSED(isSuccess);
2474 memset(&context, 0, sizeof(UseCaseContext_t));
2475 context.type = STATUS_USE_CASE;
2476 context.stepCallback = quitCallback;
2477 context.currentPage = 0;
2478 context.nbPages = 1;
2479
2481 NULL,
2482 message,
2483 NULL,
2484 statusButtonCallback,
2485 false,
2486 NO_FORCED_TYPE);
2487}
2488
2496 nbgl_callback_t quitCallback)
2497{
2498 const char *msg;
2499 bool isSuccess;
2500 switch (reviewStatusType) {
2502 msg = "Operation signed";
2503 isSuccess = true;
2504 break;
2506 msg = "Operation rejected";
2507 isSuccess = false;
2508 break;
2510 msg = "Transaction signed";
2511 isSuccess = true;
2512 break;
2514 msg = "Transaction rejected";
2515 isSuccess = false;
2516 break;
2518 msg = "Message signed";
2519 isSuccess = true;
2520 break;
2522 msg = "Message rejected";
2523 isSuccess = false;
2524 break;
2526 msg = "Address verified";
2527 isSuccess = true;
2528 break;
2530 msg = "Address verification cancelled";
2531 isSuccess = false;
2532 break;
2533 default:
2534 return;
2535 }
2536 nbgl_useCaseStatus(msg, isSuccess, quitCallback);
2537}
2538
2552 const nbgl_icon_details_t *icon,
2553 const char *reviewTitle,
2554 const char *reviewSubTitle,
2555 nbgl_choiceCallback_t choiceCallback)
2556{
2557 // memorize streaming operation type for future API calls
2558 streamingOpType = operationType;
2559
2560 memset(&context, 0, sizeof(UseCaseContext_t));
2561 context.type = STREAMING_START_REVIEW_USE_CASE;
2562 context.operationType = operationType;
2563 context.review.reviewTitle = reviewTitle;
2564 context.review.reviewSubTitle = reviewSubTitle;
2565 context.review.icon = icon;
2566 context.review.onChoice = choiceCallback;
2567 context.currentPage = 0;
2568 context.nbPages = 2; // Start page + trick for review continue
2569
2570 displayStreamingReviewPage(FORWARD_DIRECTION);
2571}
2572
2587 const nbgl_icon_details_t *icon,
2588 const char *reviewTitle,
2589 const char *reviewSubTitle,
2590 nbgl_choiceCallback_t choiceCallback)
2591{
2593 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
2594}
2595
2612 const nbgl_icon_details_t *icon,
2613 const char *reviewTitle,
2614 const char *reviewSubTitle,
2615 const nbgl_warning_t *warning,
2616 nbgl_choiceCallback_t choiceCallback)
2617{
2618 memset(&context, 0, sizeof(UseCaseContext_t));
2619 context.type = STREAMING_START_REVIEW_USE_CASE;
2620 context.operationType = operationType;
2621 context.review.reviewTitle = reviewTitle;
2622 context.review.reviewSubTitle = reviewSubTitle;
2623 context.review.icon = icon;
2624 context.review.onChoice = choiceCallback;
2625 context.currentPage = 0;
2626 context.nbPages = 2; // Start page + trick for review continue
2627
2628 // memorize streaming operation type for future API calls
2629 streamingOpType = operationType;
2630
2631 // if no warning at all, it's a simple review
2632 if ((warning == NULL)
2633 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2634 && (warning->reviewDetails == NULL))) {
2635 displayStreamingReviewPage(FORWARD_DIRECTION);
2636 return;
2637 }
2638 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2639 operationType |= NO_THREAT_OPERATION;
2640 }
2641 else {
2642 operationType |= RISKY_OPERATION;
2643 }
2644 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2645
2646 reviewWithWarnCtx.type = context.type;
2647 reviewWithWarnCtx.operationType = operationType;
2648 reviewWithWarnCtx.icon = icon;
2649 reviewWithWarnCtx.reviewTitle = reviewTitle;
2650 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2651 reviewWithWarnCtx.choiceCallback = choiceCallback;
2652 reviewWithWarnCtx.warning = warning;
2653
2654 // display the initial warning only of a risk/threat or blind signing
2655 if (!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2656 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2657 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN))) {
2658 displayStreamingReviewPage(FORWARD_DIRECTION);
2659 return;
2660 }
2661 displayInitialWarning();
2662}
2663
2678 nbgl_choiceCallback_t choiceCallback,
2679 nbgl_callback_t skipCallback)
2680{
2681 uint8_t curNbDataSets = context.review.nbDataSets;
2682
2683 memset(&context, 0, sizeof(UseCaseContext_t));
2684 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2685 context.operationType = streamingOpType;
2686 context.review.tagValueList = tagValueList;
2687 context.review.onChoice = choiceCallback;
2688 context.currentPage = 0;
2689 context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
2690 context.review.skipCallback = skipCallback;
2691 context.review.nbDataSets = curNbDataSets + 1;
2692
2693 displayStreamingReviewPage(FORWARD_DIRECTION);
2694}
2695
2707 nbgl_choiceCallback_t choiceCallback)
2708{
2709 nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL);
2710}
2711
2712void nbgl_useCaseReviewStreamingFinish(const char *finishTitle,
2713 nbgl_choiceCallback_t choiceCallback)
2714{
2715 memset(&context, 0, sizeof(UseCaseContext_t));
2716 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
2717 context.operationType = streamingOpType;
2718 context.review.onChoice = choiceCallback;
2719 context.review.finishTitle = finishTitle;
2720 context.currentPage = 0;
2721 context.nbPages = 2; // 2 pages at the end for accept/reject
2722
2723 displayStreamingReviewPage(FORWARD_DIRECTION);
2724}
2725
2731void nbgl_useCaseSpinner(const char *text)
2732{
2733 memset(&context, 0, sizeof(UseCaseContext_t));
2734 context.type = SPINNER_USE_CASE;
2735 context.currentPage = 0;
2736 context.nbPages = 1;
2737
2738 displaySpinner(text);
2739}
2740
2754 const char *message,
2755 const char *subMessage,
2756 const char *confirmText,
2757 const char *cancelText,
2758 nbgl_choiceCallback_t callback)
2759{
2761 icon, message, subMessage, confirmText, cancelText, NULL, callback);
2762};
2763
2779 const char *message,
2780 const char *subMessage,
2781 const char *confirmText,
2782 const char *cancelText,
2783 nbgl_genericDetails_t *details,
2784 nbgl_choiceCallback_t callback)
2785{
2786 memset(&context, 0, sizeof(UseCaseContext_t));
2787 context.type = CHOICE_USE_CASE;
2788 context.choice.icon = icon;
2789 context.choice.message = message;
2790 context.choice.subMessage = subMessage;
2791 context.choice.confirmText = confirmText;
2792 context.choice.cancelText = cancelText;
2793 context.choice.onChoice = callback;
2794 context.choice.details = details;
2795 context.currentPage = 0;
2796 context.nbPages = 2; // 2 pages for confirm/cancel
2797 if (message != NULL) {
2798 context.nbPages++;
2799 // if both icon and subMessage are non NULL, add a page
2800 if ((icon != NULL) && (subMessage != NULL)) {
2801 context.nbPages++;
2802 }
2803 }
2804 if (details != NULL) {
2805 // only the first level of details and BAR_LIST type are supported
2806 if (details->type == BAR_LIST_WARNING) {
2807 context.nbPages += details->barList.nbBars;
2808 }
2809 }
2810
2811 displayChoicePage(FORWARD_DIRECTION);
2812};
2813
2827void nbgl_useCaseConfirm(const char *message,
2828 const char *subMessage,
2829 const char *confirmText,
2830 const char *cancelText,
2831 nbgl_callback_t callback)
2832{
2833 memset(&context, 0, sizeof(UseCaseContext_t));
2834 context.type = CONFIRM_USE_CASE;
2835 context.confirm.message = message;
2836 context.confirm.subMessage = subMessage;
2837 context.confirm.confirmText = confirmText;
2838 context.confirm.cancelText = cancelText;
2839 context.confirm.onConfirm = callback;
2840 context.currentPage = 0;
2841 context.nbPages = 1 + 2; // 2 pages at the end for confirm/cancel
2842
2843 displayConfirm(FORWARD_DIRECTION);
2844}
2845
2856 const char *message,
2857 const char *actionText,
2858 nbgl_callback_t callback)
2859{
2860 nbgl_layoutCenteredInfo_t centeredInfo = {0};
2861
2862 UNUSED(actionText);
2863
2864 // memorize callback in context
2865 memset(&context, 0, sizeof(UseCaseContext_t));
2866 context.type = ACTION_USE_CASE;
2867 context.action.actionCallback = callback;
2868
2869 centeredInfo.icon = icon;
2870 centeredInfo.text1 = message;
2871 centeredInfo.style = BOLD_TEXT1_INFO;
2872 nbgl_stepDrawCenteredInfo(0, useCaseActionCallback, NULL, &centeredInfo, false);
2873}
2874
2875#ifdef NBGL_KEYPAD
2893void nbgl_useCaseKeypadDigits(const char *title,
2894 uint8_t minDigits,
2895 uint8_t maxDigits,
2896 bool shuffled,
2897 nbgl_pinValidCallback_t validatePinCallback,
2898 nbgl_callback_t backCallback)
2899{
2900 keypadGenericUseCase(
2901 title, minDigits, maxDigits, shuffled, false, validatePinCallback, backCallback);
2902}
2903
2922void nbgl_useCaseKeypadPIN(const char *title,
2923 uint8_t minDigits,
2924 uint8_t maxDigits,
2925 bool shuffled,
2926 nbgl_pinValidCallback_t validatePinCallback,
2927 nbgl_callback_t backCallback)
2928{
2929 keypadGenericUseCase(
2930 title, minDigits, maxDigits, shuffled, true, validatePinCallback, backCallback);
2931}
2932#endif // NBGL_KEYPAD
2933
2934#endif // HAVE_SE_TOUCH
2935#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:1669
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.
@ 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