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
45#define REAL_TYPE_MASK 0x7
46
47/**********************
48 * TYPEDEFS
49 **********************/
50
51typedef struct ReviewContext_s {
52 nbgl_choiceCallback_t onChoice;
53 const nbgl_contentTagValueList_t *tagValueList;
54 const nbgl_icon_details_t *icon;
55 const char *reviewTitle;
56 const char *reviewSubTitle;
57 const char *address; // for address confirmation review
58 nbgl_callback_t skipCallback; // callback provided by used
59 uint8_t nbDataSets; // number of sets of data received by StreamingContinue
60 bool skipDisplay; // if set to true, means that we are displaying the skip page
61 uint8_t dataDirection; // used to know whether the skip page is reached from back or forward
62 uint8_t currentTagValueIndex;
63 uint8_t currentExtensionPage;
64 uint8_t nbExtensionPages;
65 const nbgl_contentValueExt_t *extension;
66 nbgl_step_t extensionStepCtx;
67
68} ReviewContext_t;
69
70typedef struct ChoiceContext_s {
71 const nbgl_icon_details_t *icon;
72 const char *message;
73 const char *subMessage;
74 const char *confirmText;
75 const char *cancelText;
76 nbgl_choiceCallback_t onChoice;
77} ChoiceContext_t;
78
79typedef struct ConfirmContext_s {
80 const char *message;
81 const char *subMessage;
82 const char *confirmText;
83 const char *cancelText;
84 nbgl_callback_t onConfirm;
85 nbgl_step_t currentStep;
86} ConfirmContext_t;
87
88typedef struct ContentContext_s {
89 const char *title; // For CHOICES_LIST /BARS_LIST
90 nbgl_genericContents_t genericContents;
91 const char *rejectText;
92 nbgl_layoutTouchCallback_t controlsCallback;
93 nbgl_callback_t quitCallback;
94} ContentContext_t;
95
96typedef struct HomeContext_s {
97 const char *appName;
98 const nbgl_icon_details_t *appIcon;
99 const char *tagline;
100 const nbgl_genericContents_t *settingContents;
101 const nbgl_contentInfoList_t *infosList;
102 const nbgl_homeAction_t *homeAction;
103 nbgl_callback_t quitCallback;
104} HomeContext_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} ContextType_t;
139
140typedef struct UseCaseContext_s {
141 ContextType_t type;
142 nbgl_operationType_t operationType;
143 uint8_t nbPages;
144 int8_t currentPage;
146 stepCallback;
147 union {
148 ReviewContext_t review;
149 ChoiceContext_t choice;
150 ConfirmContext_t confirm;
151 HomeContext_t home;
152 ContentContext_t content;
153#ifdef NBGL_KEYPAD
154 KeypadContext_t keypad;
155#endif
156 };
157} UseCaseContext_t;
158
159typedef struct PageContent_s {
160 bool isSwitch;
161 const char *text;
162 const char *subText;
163 const nbgl_icon_details_t *icon;
164 const nbgl_contentValueExt_t *extension;
165 nbgl_state_t state;
166} PageContent_t;
167
168typedef struct ReviewWithWarningContext_s {
169 ContextType_t type;
170 nbgl_operationType_t operationType;
171 const nbgl_contentTagValueList_t *tagValueList;
172 const nbgl_icon_details_t *icon;
173 const char *reviewTitle;
174 const char *reviewSubTitle;
175 const char *finishTitle;
176 const nbgl_warning_t *warning;
177 nbgl_choiceCallback_t choiceCallback;
178 uint8_t securityReportLevel; // level 1 is the first level of menus
179 bool isIntro; // set to true during intro (before actual review)
180 uint8_t warningPage;
181 uint8_t nbWarningPages;
182} ReviewWithWarningContext_t;
183
184typedef enum {
185 NO_FORCED_TYPE = 0,
186 FORCE_BUTTON,
187 FORCE_CENTERED_INFO
188} ForcedType_t;
189
190/**********************
191 * STATIC VARIABLES
192 **********************/
193static UseCaseContext_t context;
194
195static ReviewWithWarningContext_t reviewWithWarnCtx;
196// configuration of warning when using @ref nbgl_useCaseReviewBlindSigning()
197static const nbgl_warning_t blindSigningWarning = {.predefinedSet = (1 << BLIND_SIGNING_WARN)};
198
199/**********************
200 * STATIC FUNCTIONS
201 **********************/
202static void displayReviewPage(nbgl_stepPosition_t pos);
203static void displayStreamingReviewPage(nbgl_stepPosition_t pos);
204static void displayHomePage(nbgl_stepPosition_t pos);
205static void displayInfoPage(nbgl_stepPosition_t pos);
206static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state);
207static void displayChoicePage(nbgl_stepPosition_t pos);
208static void displayConfirm(nbgl_stepPosition_t pos);
209static void displayContent(nbgl_stepPosition_t pos, bool toogle_state);
210static void displaySpinner(const char *text);
211
212static void startUseCaseHome(void);
213static void startUseCaseInfo(void);
214static void startUseCaseSettings(void);
215static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
216static void startUseCaseContent(void);
217
218static void statusTickerCallback(void);
219
220static void displayExtensionStep(nbgl_stepPosition_t pos);
221static void displayWarningStep(void);
222
223// Simple helper to get the number of elements inside a nbgl_content_t
224static uint8_t getContentNbElement(const nbgl_content_t *content)
225{
226 switch (content->type) {
227 case CENTERED_INFO:
228 return 1;
229 case INFO_BUTTON:
230 return 1;
231 case TAG_VALUE_LIST:
232 return content->content.tagValueList.nbPairs;
233 case SWITCHES_LIST:
234 return content->content.switchesList.nbSwitches;
235 case INFOS_LIST:
236 return content->content.infosList.nbInfos;
237 case CHOICES_LIST:
238 return content->content.choicesList.nbChoices;
239 case BARS_LIST:
240 return content->content.barsList.nbBars;
241 default:
242 return 0;
243 }
244}
245
246// Helper to retrieve the content inside a nbgl_genericContents_t using
247// either the contentsList or using the contentGetterCallback
248static const nbgl_content_t *getContentAtIdx(const nbgl_genericContents_t *genericContents,
249 int8_t contentIdx,
250 nbgl_content_t *content)
251{
252 if (contentIdx < 0 || contentIdx >= genericContents->nbContents) {
253 LOG_DEBUG(USE_CASE_LOGGER, "No content available at %d\n", contentIdx);
254 return NULL;
255 }
256
257 if (genericContents->callbackCallNeeded) {
258 if (content == NULL) {
259 LOG_DEBUG(USE_CASE_LOGGER, "Invalid content variable\n");
260 return NULL;
261 }
262 // Retrieve content through callback, but first memset the content.
263 memset(content, 0, sizeof(nbgl_content_t));
264 genericContents->contentGetterCallback(contentIdx, content);
265 return content;
266 }
267 else {
268 // Retrieve content through list
269 return PIC(&genericContents->contentsList[contentIdx]);
270 }
271}
272
273// Helper to retrieve the content inside a nbgl_genericContents_t using
274// either the contentsList or using the contentGetterCallback
275static const nbgl_content_t *getContentElemAtIdx(uint8_t elemIdx,
276 uint8_t *elemContentIdx,
277 nbgl_content_t *content)
278{
279 const nbgl_genericContents_t *genericContents = NULL;
280 const nbgl_content_t *p_content = NULL;
281 uint8_t nbPages = 0;
282 uint8_t elemNbPages = 0;
283
284 switch (context.type) {
285 case SETTINGS_USE_CASE:
286 case HOME_USE_CASE:
287 case GENERIC_SETTINGS:
288 genericContents = context.home.settingContents;
289 break;
290 case CONTENT_USE_CASE:
291 case GENERIC_REVIEW_USE_CASE:
292 genericContents = &context.content.genericContents;
293 break;
294 default:
295 return NULL;
296 }
297 for (int i = 0; i < genericContents->nbContents; i++) {
298 p_content = getContentAtIdx(genericContents, i, content);
299 elemNbPages = getContentNbElement(p_content);
300 if (nbPages + elemNbPages > elemIdx) {
301 *elemContentIdx = context.currentPage - nbPages;
302 break;
303 }
304 nbPages += elemNbPages;
305 }
306
307 return p_content;
308}
309
310static const char *getChoiceName(uint8_t choiceIndex)
311{
312 uint8_t elemIdx;
313 uint8_t nbValues;
314 const nbgl_content_t *p_content = NULL;
315 nbgl_content_t content = {0};
316 nbgl_contentRadioChoice_t *contentChoices = NULL;
317 nbgl_contentBarsList_t *contentBars = NULL;
318 char **names = NULL;
319
320 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
321 if (p_content == NULL) {
322 return NULL;
323 }
324 switch (p_content->type) {
325 case CHOICES_LIST:
326 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
327 names = (char **) PIC(contentChoices->names);
328 nbValues = contentChoices->nbChoices;
329 break;
330 case BARS_LIST:
331 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
332 names = (char **) PIC(contentBars->barTexts);
333 nbValues = contentBars->nbBars;
334 break;
335 default:
336 // Not supported as vertical MenuList
337 return NULL;
338 }
339 if (choiceIndex >= nbValues) {
340 // Last item is always "Back" button
341 return "Back";
342 }
343 return (const char *) PIC(names[choiceIndex]);
344}
345
346static void onChoiceSelected(uint8_t choiceIndex)
347{
348 uint8_t elemIdx;
349 uint8_t token = 255;
350 const nbgl_content_t *p_content = NULL;
351 nbgl_content_t content = {0};
352 nbgl_contentRadioChoice_t *contentChoices = NULL;
353 nbgl_contentBarsList_t *contentBars = NULL;
354
355 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
356 if (p_content == NULL) {
357 return;
358 }
359 switch (p_content->type) {
360 case CHOICES_LIST:
361 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
362 if (choiceIndex < contentChoices->nbChoices) {
363 token = contentChoices->token;
364 }
365 break;
366 case BARS_LIST:
367 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
368 if (choiceIndex < contentBars->nbBars) {
369 token = contentBars->tokens[choiceIndex];
370 }
371 break;
372 default:
373 // Not supported as vertical MenuList
374 break;
375 }
376 if ((token != 255) && (context.content.controlsCallback != NULL)) {
377 context.content.controlsCallback(token, 0);
378 }
379 else if (context.content.quitCallback != NULL) {
380 context.content.quitCallback();
381 }
382}
383
384static void getPairData(const nbgl_contentTagValueList_t *tagValueList,
385 uint8_t index,
386 const char **item,
387 const char **value,
388 const nbgl_contentValueExt_t **extension)
389{
390 const nbgl_contentTagValue_t *pair;
391
392 if (tagValueList->pairs != NULL) {
393 pair = PIC(&tagValueList->pairs[index]);
394 }
395 else {
396 pair = PIC(tagValueList->callback(index));
397 }
398 *item = pair->item;
399 *value = pair->value;
400 if (pair->aliasValue) {
401 *extension = pair->extension;
402 }
403 else {
404 *extension = NULL;
405 }
406}
407
408static void onReviewAccept(void)
409{
410 if (context.review.onChoice) {
411 context.review.onChoice(true);
412 }
413}
414
415static void onReviewReject(void)
416{
417 if (context.review.onChoice) {
418 context.review.onChoice(false);
419 }
420}
421
422static void onChoiceAccept(void)
423{
424 if (context.choice.onChoice) {
425 context.choice.onChoice(true);
426 }
427}
428
429static void onChoiceReject(void)
430{
431 if (context.choice.onChoice) {
432 context.choice.onChoice(false);
433 }
434}
435
436static void onConfirmAccept(void)
437{
438 if (context.confirm.currentStep) {
439 nbgl_stepRelease(context.confirm.currentStep);
440 }
441 if (context.confirm.onConfirm) {
442 context.confirm.onConfirm();
443 }
444}
445
446static void onConfirmReject(void)
447{
448 if (context.confirm.currentStep) {
449 nbgl_stepRelease(context.confirm.currentStep);
451 nbgl_refresh();
452 }
453}
454
455static void onSwitchAction(void)
456{
457 const nbgl_contentSwitch_t *contentSwitch = NULL;
458 const nbgl_content_t *p_content = NULL;
459 nbgl_content_t content = {0};
460 uint8_t elemIdx;
461
462 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
463 if ((p_content == NULL) || (p_content->type != SWITCHES_LIST)) {
464 return;
465 }
466 contentSwitch
467 = &((const nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
468 switch (context.type) {
469 case SETTINGS_USE_CASE:
470 case HOME_USE_CASE:
471 case GENERIC_SETTINGS:
472 displaySettingsPage(FORWARD_DIRECTION, true);
473 break;
474 case CONTENT_USE_CASE:
475 case GENERIC_REVIEW_USE_CASE:
476 displayContent(FORWARD_DIRECTION, true);
477 break;
478 default:
479 break;
480 }
481 if (p_content->contentActionCallback != NULL) {
482 nbgl_contentActionCallback_t actionCallback = PIC(p_content->contentActionCallback);
483 actionCallback(contentSwitch->token,
484 (contentSwitch->initState == ON_STATE) ? OFF_STATE : ON_STATE,
485 context.currentPage);
486 }
487 else if (context.content.controlsCallback != NULL) {
488 context.content.controlsCallback(contentSwitch->token, 0);
489 }
490}
491
492static void drawStep(nbgl_stepPosition_t pos,
493 const nbgl_icon_details_t *icon,
494 const char *txt,
495 const char *subTxt,
496 nbgl_stepButtonCallback_t onActionCallback,
497 bool modal,
498 ForcedType_t forcedType)
499{
500 uint8_t elemIdx;
501 nbgl_step_t newStep = NULL;
502 const nbgl_content_t *p_content = NULL;
503 nbgl_content_t content = {0};
504 nbgl_contentRadioChoice_t *contentChoices = NULL;
505 nbgl_contentBarsList_t *contentBars = NULL;
506 nbgl_screenTickerConfiguration_t *p_ticker = NULL;
507 nbgl_layoutMenuList_t list = {0};
508 nbgl_screenTickerConfiguration_t ticker = {.tickerCallback = PIC(statusTickerCallback),
509 .tickerIntervale = 0, // not periodic
510 .tickerValue = STATUS_SCREEN_DURATION};
511
512 pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
513 // if we are in streaming+skip case, enable going backward even for first tag/value of the set
514 // (except the first set) because the set starts with a "skip" page
515 if ((context.type == STREAMING_CONTINUE_REVIEW_USE_CASE)
516 && (context.review.skipCallback != NULL) && (context.review.nbDataSets > 1)) {
517 pos |= LAST_STEP;
518 }
519 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
520 p_ticker = &ticker;
521 }
522 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
523 nbgl_stepRelease(context.confirm.currentStep);
524 }
525
526 if (txt == NULL) {
527 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
528 if (p_content) {
529 switch (p_content->type) {
530 case CHOICES_LIST:
531 contentChoices
532 = ((nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList));
533 list.nbChoices = contentChoices->nbChoices + 1; // For Back button
534 list.selectedChoice = contentChoices->initChoice;
535 list.callback = getChoiceName;
536 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
537 break;
538 case BARS_LIST:
539 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
540 list.nbChoices = contentBars->nbBars + 1; // For Back button
541 list.selectedChoice = 0;
542 list.callback = getChoiceName;
543 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
544 break;
545 default:
546 // Not supported as vertical MenuList
547 break;
548 }
549 }
550 }
551 else if ((icon == NULL) && (forcedType != FORCE_CENTERED_INFO)) {
553 if (subTxt != NULL) {
554 style = (forcedType == FORCE_BUTTON) ? BUTTON_INFO : BOLD_TEXT1_INFO;
555 }
556 else {
557 style = REGULAR_INFO;
558 }
559 newStep = nbgl_stepDrawText(pos, onActionCallback, p_ticker, txt, subTxt, style, modal);
560 }
561 else {
563 info.icon = icon;
564 info.text1 = txt;
565 info.text2 = subTxt;
566 info.onTop = false;
567 if ((subTxt != NULL) || (context.stepCallback != NULL)) {
568 info.style = BOLD_TEXT1_INFO;
569 }
570 else {
571 info.style = REGULAR_INFO;
572 }
573 newStep = nbgl_stepDrawCenteredInfo(pos, onActionCallback, p_ticker, &info, modal);
574 }
575 if (context.type == CONFIRM_USE_CASE) {
576 context.confirm.currentStep = newStep;
577 }
578}
579
580static void drawSwitchStep(nbgl_stepPosition_t pos,
581 const char *title,
582 const char *description,
583 bool state,
584 nbgl_stepButtonCallback_t onActionCallback,
585 bool modal)
586{
587 nbgl_layoutSwitch_t switchInfo;
588
589 pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
590 switchInfo.initState = state;
591 switchInfo.text = title;
592 switchInfo.subText = description;
593 nbgl_stepDrawSwitch(pos, onActionCallback, NULL, &switchInfo, modal);
594}
595
596static bool buttonGenericCallback(nbgl_buttonEvent_t event, nbgl_stepPosition_t *pos)
597{
598 uint8_t elemIdx;
599 uint8_t token = 0;
600 uint8_t index = 0;
601 const nbgl_content_t *p_content = NULL;
602 nbgl_content_t content = {0};
603
604 if (event == BUTTON_LEFT_PRESSED) {
605 if (context.currentPage > 0) {
606 context.currentPage--;
607 }
608 // in streaming+skip case, it is allowed to go backward at the first tag/value, except for
609 // the first set
610 else if ((context.type != STREAMING_CONTINUE_REVIEW_USE_CASE)
611 || (context.review.skipCallback == NULL) || (context.review.nbDataSets == 1)) {
612 // Drop the event
613 return false;
614 }
615 *pos = BACKWARD_DIRECTION;
616 }
617 else if (event == BUTTON_RIGHT_PRESSED) {
618 if (context.currentPage < (int) (context.nbPages - 1)) {
619 context.currentPage++;
620 }
621 else {
622 // Drop the event
623 return false;
624 }
625 *pos = FORWARD_DIRECTION;
626 }
627 else {
628 if (event == BUTTON_BOTH_PRESSED) {
629 if (context.stepCallback != NULL) {
630 context.stepCallback();
631 }
632 else if ((context.type == CONTENT_USE_CASE)
633 || (context.type == GENERIC_REVIEW_USE_CASE)) {
634 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
635 if (p_content != NULL) {
636 switch (p_content->type) {
637 case CENTERED_INFO:
638 // No associated callback
639 return false;
640 case INFO_BUTTON:
641 token = p_content->content.infoButton.buttonToken;
642 break;
643 case SWITCHES_LIST:
644 token = p_content->content.switchesList.switches->token;
645 break;
646 case BARS_LIST:
647 token = p_content->content.barsList.tokens[context.currentPage];
648 break;
649 case CHOICES_LIST:
650 token = p_content->content.choicesList.token;
651 index = context.currentPage;
652 break;
653 default:
654 break;
655 }
656
657 if ((p_content) && (p_content->contentActionCallback != NULL)) {
658 p_content->contentActionCallback(token, 0, context.currentPage);
659 }
660 else if (context.content.controlsCallback != NULL) {
661 context.content.controlsCallback(token, index);
662 }
663 }
664 }
665 }
666 return false;
667 }
668 return true;
669}
670
671static void reviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
672{
673 UNUSED(stepCtx);
675
676 if (!buttonGenericCallback(event, &pos)) {
677 return;
678 }
679
680 displayReviewPage(pos);
681}
682
683// this is the callback used when button action on the "skip" page
684static void buttonSkipCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
685{
686 UNUSED(stepCtx);
688
689 if (event == BUTTON_LEFT_PRESSED) {
690 // only decrement page if we are going backward but coming from forward (back & forth)
691 if ((context.review.dataDirection == FORWARD_DIRECTION) && (context.currentPage > 0)) {
692 context.currentPage--;
693 }
694 pos = BACKWARD_DIRECTION;
695 }
696 else if (event == BUTTON_RIGHT_PRESSED) {
697 // only increment page if we are going forward but coming from backward (back & forth)
698 if ((context.review.dataDirection == BACKWARD_DIRECTION)
699 && (context.currentPage < (int) (context.nbPages - 1)) && (context.currentPage > 0)) {
700 context.currentPage++;
701 }
702 pos = FORWARD_DIRECTION;
703 }
704 else if (event == BUTTON_BOTH_PRESSED) {
705 context.review.skipCallback();
706 return;
707 }
708 else {
709 return;
710 }
711 displayStreamingReviewPage(pos);
712}
713
714static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
715{
717 UNUSED(stepCtx);
718
719 if (!buttonGenericCallback(event, &pos)) {
720 return;
721 }
722 else {
723 // memorize last direction
724 context.review.dataDirection = pos;
725 }
726
727 displayStreamingReviewPage(pos);
728}
729
730static void settingsCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
731{
732 UNUSED(stepCtx);
734
735 if (!buttonGenericCallback(event, &pos)) {
736 return;
737 }
738
739 displaySettingsPage(pos, false);
740}
741
742static void infoCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
743{
744 UNUSED(stepCtx);
746
747 if (!buttonGenericCallback(event, &pos)) {
748 return;
749 }
750
751 displayInfoPage(pos);
752}
753
754static void homeCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
755{
756 UNUSED(stepCtx);
758
759 if (!buttonGenericCallback(event, &pos)) {
760 return;
761 }
762
763 displayHomePage(pos);
764}
765
766static void genericChoiceCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
767{
768 UNUSED(stepCtx);
770
771 if (!buttonGenericCallback(event, &pos)) {
772 return;
773 }
774
775 displayChoicePage(pos);
776}
777
778static void genericConfirmCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
779{
780 UNUSED(stepCtx);
782
783 if (!buttonGenericCallback(event, &pos)) {
784 return;
785 }
786
787 displayConfirm(pos);
788}
789
790static void statusButtonCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
791{
792 UNUSED(stepCtx);
793 if (event == BUTTON_BOTH_PRESSED) {
794 if (context.stepCallback != NULL) {
795 context.stepCallback();
796 }
797 }
798}
799
800static void contentCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
801{
802 UNUSED(stepCtx);
804
805 if (!buttonGenericCallback(event, &pos)) {
806 return;
807 }
808
809 displayContent(pos, false);
810}
811
812// callback used for timeout
813static void statusTickerCallback(void)
814{
815 if (context.stepCallback != NULL) {
816 context.stepCallback();
817 }
818}
819
820// this is the callback used when navigating in extension pages
821static void extensionNavigate(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
822{
824 UNUSED(stepCtx);
825
826 if (event == BUTTON_LEFT_PRESSED) {
827 // only decrement page if we are not at the first page
828 if (context.review.currentExtensionPage > 0) {
829 context.review.currentExtensionPage--;
830 }
831 pos = BACKWARD_DIRECTION;
832 }
833 else if (event == BUTTON_RIGHT_PRESSED) {
834 // only increment page if not at last page
835 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
836 context.review.currentExtensionPage++;
837 }
838 pos = FORWARD_DIRECTION;
839 }
840 else if (event == BUTTON_BOTH_PRESSED) {
841 // if at last page, leave modal context
842 if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
843 nbgl_stepRelease(context.review.extensionStepCtx);
845 nbgl_refresh();
846 }
847 return;
848 }
849 else {
850 return;
851 }
852 displayExtensionStep(pos);
853}
854
855// function used to display the extension pages
856static void displayExtensionStep(nbgl_stepPosition_t pos)
857{
858 nbgl_layoutCenteredInfo_t info = {0};
859
860 if (context.review.extensionStepCtx != NULL) {
861 nbgl_stepRelease(context.review.extensionStepCtx);
862 }
863 if (context.review.currentExtensionPage < (context.review.nbExtensionPages - 1)) {
864 if (context.review.currentExtensionPage == 0) {
865 pos |= FIRST_STEP;
866 }
867 else {
869 }
870
871 if (context.review.extension->aliasType == ENS_ALIAS) {
872 context.review.extensionStepCtx = nbgl_stepDrawText(pos,
873 extensionNavigate,
874 NULL,
875 context.review.extension->title,
876 context.review.extension->fullValue,
877 BOLD_TEXT1_INFO,
878 true);
879 }
880 else if (context.review.extension->aliasType == INFO_LIST_ALIAS) {
881 context.review.extensionStepCtx = nbgl_stepDrawText(
882 pos,
883 extensionNavigate,
884 NULL,
885 context.review.extension->infolist->infoTypes[context.review.currentExtensionPage],
886 context.review.extension->infolist
887 ->infoContents[context.review.currentExtensionPage],
888 BOLD_TEXT1_INFO,
889 true);
890 }
891 }
892 else if (context.review.currentExtensionPage == (context.review.nbExtensionPages - 1)) {
893 // draw the back page
894 info.icon = &C_icon_back_x;
895 info.text1 = "Back";
896 info.style = BOLD_TEXT1_INFO;
897 pos |= LAST_STEP;
898 context.review.extensionStepCtx
899 = nbgl_stepDrawCenteredInfo(pos, extensionNavigate, NULL, &info, true);
900 }
901 nbgl_refresh();
902}
903
904static void displayAliasFullValue(void)
905{
906 const char *text = NULL;
907 const char *subText = NULL;
908
909 getPairData(context.review.tagValueList,
910 context.review.currentTagValueIndex,
911 &text,
912 &subText,
913 &context.review.extension);
914 if (context.review.extension == NULL) {
915 // probably an error
917 "displayAliasFullValue: extension nor found for pair %d\n",
918 context.review.currentTagValueIndex);
919 return;
920 }
921 context.review.currentExtensionPage = 0;
922 context.review.extensionStepCtx = NULL;
923 // create a modal flow to display this extension
924 if (context.review.extension->aliasType == ENS_ALIAS) {
925 context.review.nbExtensionPages = 2;
926 }
927 else if (context.review.extension->aliasType == INFO_LIST_ALIAS) {
928 context.review.nbExtensionPages = context.review.extension->infolist->nbInfos + 1;
929 }
930 else {
932 "displayAliasFullValue: unsupported alias type %d\n",
933 context.review.extension->aliasType);
934 return;
935 }
936 displayExtensionStep(FORWARD_DIRECTION);
937}
938
939static void getLastPageInfo(bool approve, const nbgl_icon_details_t **icon, const char **text)
940{
941 if (approve) {
942 // Approve page
943 *icon = &C_icon_validate_14;
944 if (context.type == ADDRESS_REVIEW_USE_CASE) {
945 *text = "Confirm";
946 }
947 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_TRANSACTION) {
948 if (context.operationType & RISKY_OPERATION) {
949 *text = "Accept risk and sign transaction";
950 }
951 else {
952 *text = "Sign transaction";
953 }
954 }
955 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_MESSAGE) {
956 if (context.operationType & RISKY_OPERATION) {
957 *text = "Accept risk and sign message";
958 }
959 else {
960 *text = "Sign message";
961 };
962 }
963 else {
964 if (context.operationType & RISKY_OPERATION) {
965 *text = "Accept risk and sign operation";
966 }
967 else {
968 *text = "Sign operation";
969 }
970 }
971 context.stepCallback = onReviewAccept;
972 }
973 else {
974 // Reject page
975 *icon = &C_icon_crossmark;
976 if (context.type == ADDRESS_REVIEW_USE_CASE) {
977 *text = "Cancel";
978 }
979 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_TRANSACTION) {
980 *text = "Reject transaction";
981 }
982 else if ((context.operationType & REAL_TYPE_MASK) == TYPE_MESSAGE) {
983 *text = "Reject message";
984 }
985 else {
986 *text = "Reject operation";
987 }
988 context.stepCallback = onReviewReject;
989 }
990}
991
992// function used to display the current page in review
993static void displayReviewPage(nbgl_stepPosition_t pos)
994{
995 uint8_t reviewPages = 0;
996 uint8_t finalPages = 0;
997 uint8_t pairIndex = 0;
998 const char *text = NULL;
999 const char *subText = NULL;
1000 const nbgl_icon_details_t *icon = NULL;
1001 uint8_t currentIndex = 0;
1002 uint8_t titleIndex = 255;
1003 uint8_t subIndex = 255;
1004 uint8_t approveIndex = 255;
1005 uint8_t rejectIndex = 255;
1006 const nbgl_contentValueExt_t *extension = NULL;
1007
1008 context.stepCallback = NULL;
1009
1010 // Determine the 1st page to display tag/values
1011 // Title page to display
1012 titleIndex = currentIndex++;
1013 reviewPages++;
1014 if (context.review.reviewSubTitle) {
1015 // subtitle page to display
1016 subIndex = currentIndex++;
1017 reviewPages++;
1018 }
1019 approveIndex = context.nbPages - 2;
1020 rejectIndex = context.nbPages - 1;
1021 finalPages = approveIndex;
1022
1023 // Determine which page to display
1024 if (context.currentPage >= finalPages) {
1025 if (context.currentPage == approveIndex) {
1026 // Approve page
1027 getLastPageInfo(true, &icon, &text);
1028 }
1029 else if (context.currentPage == rejectIndex) {
1030 // Reject page
1031 getLastPageInfo(false, &icon, &text);
1032 }
1033 }
1034 else if (context.currentPage < reviewPages) {
1035 if (context.currentPage == titleIndex) {
1036 // Title page
1037 icon = context.review.icon;
1038 text = context.review.reviewTitle;
1039 }
1040 else if (context.currentPage == subIndex) {
1041 // SubTitle page
1042 text = context.review.reviewSubTitle;
1043 }
1044 }
1045 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
1046 // address confirmation and 2nd page
1047 text = "Address";
1048 subText = context.review.address;
1049 }
1050 else {
1051 pairIndex = context.currentPage - reviewPages;
1052 if (context.review.address != NULL) {
1053 pairIndex--;
1054 }
1055 getPairData(context.review.tagValueList, pairIndex, &text, &subText, &extension);
1056 if (extension != NULL) {
1057 context.stepCallback = displayAliasFullValue;
1058 context.review.currentTagValueIndex = pairIndex;
1059 }
1060 }
1061
1062 drawStep(pos,
1063 icon,
1064 text,
1065 subText,
1066 reviewCallback,
1067 false,
1068 (extension != NULL) ? FORCE_BUTTON : NO_FORCED_TYPE);
1069 nbgl_refresh();
1070}
1071
1072// function used to display the current page in review
1073static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
1074{
1075 const char *text = NULL;
1076 const char *subText = NULL;
1077 const nbgl_icon_details_t *icon = NULL;
1078 uint8_t reviewPages = 0;
1079 uint8_t titleIndex = 255;
1080 uint8_t subIndex = 255;
1081 const nbgl_contentValueExt_t *extension = NULL;
1082
1083 context.stepCallback = NULL;
1084 switch (context.type) {
1085 case STREAMING_START_REVIEW_USE_CASE:
1086 // Title page to display
1087 titleIndex = reviewPages++;
1088 if (context.review.reviewSubTitle) {
1089 // subtitle page to display
1090 subIndex = reviewPages++;
1091 }
1092 // Determine which page to display
1093 if (context.currentPage >= reviewPages) {
1094 onReviewAccept();
1095 return;
1096 }
1097 // header page(s)
1098 if (context.currentPage == titleIndex) {
1099 // title page
1100 icon = context.review.icon;
1101 text = context.review.reviewTitle;
1102 }
1103 else if (context.currentPage == subIndex) {
1104 // subtitle page
1105 text = context.review.reviewSubTitle;
1106 }
1107 break;
1108
1109 case STREAMING_CONTINUE_REVIEW_USE_CASE:
1110 if (context.currentPage >= context.review.tagValueList->nbPairs) {
1111 onReviewAccept();
1112 return;
1113 }
1114 // if there is a skip, and we are not already displaying the "skip" page
1115 // and we are not at the first tag/value of the first set of data (except if going
1116 // backward) then display the "skip" page
1117 if ((context.review.skipCallback != NULL) && (context.review.skipDisplay == false)
1118 && ((context.review.nbDataSets > 1) || (context.currentPage > 0)
1119 || (context.review.dataDirection == BACKWARD_DIRECTION))) {
1120 nbgl_stepPosition_t directions = (pos & BACKWARD_DIRECTION) | FIRST_STEP;
1121 nbgl_layoutCenteredInfo_t info = {0};
1122 if ((context.review.nbDataSets == 1) || (context.currentPage > 0)) {
1123 directions |= LAST_STEP;
1124 }
1125 info.icon = &C_Information_circle_14px;
1126 info.text1 = "Press right button to continue message or \bpress both to skip\b";
1127 nbgl_stepDrawCenteredInfo(directions, buttonSkipCallback, NULL, &info, false);
1128 nbgl_refresh();
1129 context.review.skipDisplay = true;
1130 return;
1131 }
1132 context.review.skipDisplay = false;
1133 getPairData(
1134 context.review.tagValueList, context.currentPage, &text, &subText, &extension);
1135 break;
1136
1137 case STREAMING_FINISH_REVIEW_USE_CASE:
1138 default:
1139 if (context.currentPage == 0) {
1140 // accept page
1141 getLastPageInfo(true, &icon, &text);
1142 }
1143 else {
1144 // reject page
1145 getLastPageInfo(false, &icon, &text);
1146 }
1147 break;
1148 }
1149
1150 drawStep(pos,
1151 icon,
1152 text,
1153 subText,
1154 streamingReviewCallback,
1155 false,
1156 (extension != NULL) ? FORCE_BUTTON : NO_FORCED_TYPE);
1157 nbgl_refresh();
1158}
1159
1160// function used to display the current page in info
1161static void displayInfoPage(nbgl_stepPosition_t pos)
1162{
1163 const char *text = NULL;
1164 const char *subText = NULL;
1165 const nbgl_icon_details_t *icon = NULL;
1166
1167 context.stepCallback = NULL;
1168
1169 if (context.currentPage < (context.nbPages - 1)) {
1170 text = PIC(
1171 ((const char *const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
1172 subText = PIC(
1173 ((const char *const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
1174 }
1175 else {
1176 icon = &C_icon_back_x;
1177 text = "Back";
1178 context.stepCallback = startUseCaseHome;
1179 }
1180
1181 drawStep(pos, icon, text, subText, infoCallback, false, FORCE_CENTERED_INFO);
1182 nbgl_refresh();
1183}
1184
1185// function used to get the current page content
1186static void getContentPage(bool toogle_state, PageContent_t *contentPage)
1187{
1188 uint8_t elemIdx;
1189 const nbgl_content_t *p_content = NULL;
1190 nbgl_content_t content = {0};
1191 nbgl_contentSwitch_t *contentSwitch = NULL;
1192#ifdef WITH_HORIZONTAL_CHOICES_LIST
1193 nbgl_contentRadioChoice_t *contentChoices = NULL;
1194 char **names = NULL;
1195#endif
1196
1197 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
1198 if (p_content == NULL) {
1199 return;
1200 }
1201 switch (p_content->type) {
1202 case CENTERED_INFO:
1203 contentPage->text = PIC(p_content->content.centeredInfo.text1);
1204 contentPage->subText = PIC(p_content->content.centeredInfo.text2);
1205 break;
1206 case INFO_BUTTON:
1207 contentPage->icon = PIC(p_content->content.infoButton.icon);
1208 contentPage->text = PIC(p_content->content.infoButton.text);
1209 contentPage->subText = PIC(p_content->content.infoButton.buttonText);
1210 break;
1211 case TAG_VALUE_LIST:
1212 getPairData(&p_content->content.tagValueList,
1213 elemIdx,
1214 &contentPage->text,
1215 &contentPage->subText,
1216 &contentPage->extension);
1217 break;
1218 case SWITCHES_LIST:
1219 contentPage->isSwitch = true;
1220 contentSwitch = &(
1221 (nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
1222 contentPage->text = contentSwitch->text;
1223 contentPage->state = contentSwitch->initState;
1224 if (toogle_state) {
1225 contentPage->state = (contentPage->state == ON_STATE) ? OFF_STATE : ON_STATE;
1226 }
1227 context.stepCallback = onSwitchAction;
1228 contentPage->subText = contentSwitch->subText;
1229 break;
1230 case INFOS_LIST:
1231 contentPage->text
1232 = ((const char *const *) PIC(p_content->content.infosList.infoTypes))[elemIdx];
1233 contentPage->subText
1234 = ((const char *const *) PIC(p_content->content.infosList.infoContents))[elemIdx];
1235 break;
1236 case CHOICES_LIST:
1237#ifdef WITH_HORIZONTAL_CHOICES_LIST
1238 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1239 contentPage->text = PIC(context.content.title);
1240 contentPage->subText = PIC(p_content->content.choicesList.names[elemIdx]);
1241 }
1242 else {
1243 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
1244 names = (char **) PIC(contentChoices->names);
1245 contentPage->text = (const char *) PIC(names[elemIdx]);
1246 }
1247#endif
1248 break;
1249 case BARS_LIST:
1250#ifdef WITH_HORIZONTAL_BARS_LIST
1251 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
1252 contentPage->text = PIC(context.content.title);
1253 contentPage->subText = PIC(p_content->content.barsList.barTexts[elemIdx]);
1254 }
1255 else {
1256 contentPage->text = PIC(p_content->content.barsList.barTexts[elemIdx]);
1257 }
1258#endif
1259 break;
1260 default:
1261 break;
1262 }
1263}
1264
1265// function used to display the current page in settings
1266static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state)
1267{
1268 PageContent_t contentPage = {0};
1269
1270 context.stepCallback = NULL;
1271
1272 if (context.currentPage < (context.nbPages - 1)) {
1273 getContentPage(toogle_state, &contentPage);
1274 }
1275 else { // last page is for quit
1276 contentPage.icon = &C_icon_back_x;
1277 contentPage.text = "Back";
1278 if (context.type == GENERIC_SETTINGS) {
1279 context.stepCallback = context.home.quitCallback;
1280 }
1281 else {
1282 context.stepCallback = startUseCaseHome;
1283 }
1284 }
1285
1286 if (contentPage.isSwitch) {
1287 drawSwitchStep(
1288 pos, contentPage.text, contentPage.subText, contentPage.state, settingsCallback, false);
1289 }
1290 else {
1291 drawStep(pos,
1292 contentPage.icon,
1293 contentPage.text,
1294 contentPage.subText,
1295 settingsCallback,
1296 false,
1297 NO_FORCED_TYPE);
1298 }
1299
1300 nbgl_refresh();
1301}
1302
1303static void startUseCaseHome(void)
1304{
1305 int8_t addPages = 0;
1306 if (context.home.homeAction) {
1307 // Action page index
1308 addPages++;
1309 }
1310 switch (context.type) {
1311 case SETTINGS_USE_CASE:
1312 // Settings page index
1313 context.currentPage = 1 + addPages;
1314 break;
1315 case INFO_USE_CASE:
1316 // Info page index
1317 context.currentPage = 2 + addPages;
1318 break;
1319 default:
1320 // Home page index
1321 context.currentPage = 0;
1322 break;
1323 }
1324
1325 context.type = HOME_USE_CASE;
1326 context.nbPages = 2; // Home + Quit
1327 if (context.home.settingContents) {
1328 context.nbPages++;
1329 }
1330 if (context.home.infosList) {
1331 context.nbPages++;
1332 }
1333 if (context.home.homeAction) {
1334 context.nbPages += addPages;
1335 }
1336 displayHomePage(FORWARD_DIRECTION);
1337}
1338
1339static void startUseCaseInfo(void)
1340{
1341 context.type = INFO_USE_CASE;
1342 context.nbPages = context.home.infosList->nbInfos + 1; // For back screen
1343 context.currentPage = 0;
1344
1345 displayInfoPage(FORWARD_DIRECTION);
1346}
1347
1348static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1349{
1350 nbgl_content_t content = {0};
1351 const nbgl_content_t *p_content = NULL;
1352
1353 // if not coming from GENERIC_SETTINGS, force to SETTINGS_USE_CASE
1354 if (context.type != GENERIC_SETTINGS) {
1355 context.type = SETTINGS_USE_CASE;
1356 }
1357
1358 context.nbPages = 1; // For back screen
1359 for (int i = 0; i < context.home.settingContents->nbContents; i++) {
1360 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1361 context.nbPages += getContentNbElement(p_content);
1362 }
1363 context.currentPage = initSettingPage;
1364
1365 displaySettingsPage(FORWARD_DIRECTION, false);
1366}
1367
1368static void startUseCaseSettings(void)
1369{
1370 startUseCaseSettingsAtPage(0);
1371}
1372
1373static void startUseCaseContent(void)
1374{
1375 uint8_t contentIdx = 0;
1376 const nbgl_content_t *p_content = NULL;
1377 nbgl_content_t content = {0};
1378
1379 context.nbPages = 1; // Quit
1380
1381 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1382 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1383 context.nbPages += getContentNbElement(p_content);
1384 }
1385
1386 displayContent(FORWARD_DIRECTION, false);
1387}
1388
1389// function used to display the current page in home
1390static void displayHomePage(nbgl_stepPosition_t pos)
1391{
1392 const char *text = NULL;
1393 const char *subText = NULL;
1394 const nbgl_icon_details_t *icon = NULL;
1395 uint8_t currentIndex = 0;
1396 uint8_t homeIndex = 255;
1397 uint8_t actionIndex = 255;
1398 uint8_t settingsIndex = 255;
1399 uint8_t infoIndex = 255;
1400
1401 context.stepCallback = NULL;
1402
1403 // Determine which pages are present
1404 homeIndex = currentIndex++;
1405 if (context.home.homeAction) {
1406 actionIndex = currentIndex++;
1407 }
1408 if (context.home.settingContents) {
1409 settingsIndex = currentIndex++;
1410 }
1411 if (context.home.infosList) {
1412 infoIndex = currentIndex++;
1413 }
1414
1415 if (context.currentPage == homeIndex) {
1416 // Home page
1417 icon = context.home.appIcon;
1418 if (context.home.tagline != NULL) {
1419 text = context.home.tagline;
1420 }
1421 else {
1422 text = context.home.appName;
1423 subText = "app is ready";
1424 }
1425 }
1426 else if (context.currentPage == actionIndex) {
1427 // Action page
1428 icon = context.home.homeAction->icon;
1429 text = PIC(context.home.homeAction->text);
1430 context.stepCallback = context.home.homeAction->callback;
1431 }
1432 else if (context.currentPage == settingsIndex) {
1433 // Settings page
1434 icon = &C_icon_coggle;
1435 text = "App settings";
1436 context.stepCallback = startUseCaseSettings;
1437 }
1438 else if (context.currentPage == infoIndex) {
1439 // About page
1440 icon = &C_Information_circle_14px;
1441 text = "App info";
1442 context.stepCallback = startUseCaseInfo;
1443 }
1444 else {
1445 icon = &C_Quit_14px;
1446 text = "Quit app";
1447 context.stepCallback = context.home.quitCallback;
1448 }
1449
1450 drawStep(pos, icon, text, subText, homeCallback, false, NO_FORCED_TYPE);
1451 nbgl_refresh();
1452}
1453
1454// function used to display the current page in choice
1455static void displayChoicePage(nbgl_stepPosition_t pos)
1456{
1457 const char *text = NULL;
1458 const char *subText = NULL;
1459 const nbgl_icon_details_t *icon = NULL;
1460
1461 context.stepCallback = NULL;
1462
1463 // Handle case where there is no icon or subMessage
1464 if (context.currentPage == 1
1465 && (context.choice.icon == NULL || context.choice.subMessage == NULL)) {
1466 if (pos & BACKWARD_DIRECTION) {
1467 context.currentPage -= 1;
1468 }
1469 else {
1470 context.currentPage += 1;
1471 }
1472 }
1473
1474 if (context.currentPage == 0) { // title page
1475 text = context.choice.message;
1476 if (context.choice.icon != NULL) {
1477 icon = context.choice.icon;
1478 }
1479 else {
1480 subText = context.choice.subMessage;
1481 }
1482 }
1483 else if (context.currentPage == 1) { // sub-title page
1484 // displayed only if there is both icon and submessage
1485 text = context.choice.message;
1486 subText = context.choice.subMessage;
1487 }
1488 else if (context.currentPage == 2) { // confirm page
1489 icon = &C_icon_validate_14;
1490 text = context.choice.confirmText;
1491 context.stepCallback = onChoiceAccept;
1492 }
1493 else { // cancel page
1494 icon = &C_icon_crossmark;
1495 text = context.choice.cancelText;
1496 context.stepCallback = onChoiceReject;
1497 }
1498
1499 drawStep(pos, icon, text, subText, genericChoiceCallback, false, NO_FORCED_TYPE);
1500 nbgl_refresh();
1501}
1502
1503// function used to display the Confirm page
1504static void displayConfirm(nbgl_stepPosition_t pos)
1505{
1506 const char *text = NULL;
1507 const char *subText = NULL;
1508 const nbgl_icon_details_t *icon = NULL;
1509
1510 context.stepCallback = NULL;
1511 switch (context.currentPage) {
1512 case 0:
1513 // title page
1514 text = context.confirm.message;
1515 subText = context.confirm.subMessage;
1516 break;
1517 case 1:
1518 // confirm page
1519 icon = &C_icon_validate_14;
1520 text = context.confirm.confirmText;
1521 context.stepCallback = onConfirmAccept;
1522 break;
1523 case 2:
1524 // cancel page
1525 icon = &C_icon_crossmark;
1526 text = context.confirm.cancelText;
1527 context.stepCallback = onConfirmReject;
1528 break;
1529 }
1530
1531 drawStep(pos, icon, text, subText, genericConfirmCallback, true, NO_FORCED_TYPE);
1532 nbgl_refresh();
1533}
1534
1535// function used to display the current navigable content
1536static void displayContent(nbgl_stepPosition_t pos, bool toogle_state)
1537{
1538 PageContent_t contentPage = {0};
1539
1540 context.stepCallback = NULL;
1541
1542 if (context.currentPage < (context.nbPages - 1)) {
1543 getContentPage(toogle_state, &contentPage);
1544 }
1545 else { // last page is for quit
1546 if (context.content.rejectText) {
1547 contentPage.text = context.content.rejectText;
1548 }
1549 else {
1550 contentPage.text = "Back";
1551 }
1552 if (context.type == GENERIC_REVIEW_USE_CASE) {
1553 contentPage.icon = &C_icon_crossmark;
1554 }
1555 else {
1556 contentPage.icon = &C_icon_back_x;
1557 }
1558 context.stepCallback = context.content.quitCallback;
1559 }
1560
1561 if (contentPage.isSwitch) {
1562 drawSwitchStep(
1563 pos, contentPage.text, contentPage.subText, contentPage.state, contentCallback, false);
1564 }
1565 else {
1566 drawStep(pos,
1567 contentPage.icon,
1568 contentPage.text,
1569 contentPage.subText,
1570 contentCallback,
1571 false,
1572 NO_FORCED_TYPE);
1573 }
1574
1575 nbgl_refresh();
1576}
1577
1578static void displaySpinner(const char *text)
1579{
1580 drawStep(SINGLE_STEP, &C_icon_processing, text, NULL, NULL, false, false);
1581 nbgl_refresh();
1582}
1583
1584// function to factorize code for all simple reviews
1585static void useCaseReview(ContextType_t type,
1586 nbgl_operationType_t operationType,
1587 const nbgl_contentTagValueList_t *tagValueList,
1588 const nbgl_icon_details_t *icon,
1589 const char *reviewTitle,
1590 const char *reviewSubTitle,
1591 const char *finishTitle,
1592 nbgl_choiceCallback_t choiceCallback)
1593{
1594 UNUSED(finishTitle); // TODO dedicated screen for it?
1595
1596 memset(&context, 0, sizeof(UseCaseContext_t));
1597 context.type = type;
1598 context.operationType = operationType;
1599 context.review.tagValueList = tagValueList;
1600 context.review.reviewTitle = reviewTitle;
1601 context.review.reviewSubTitle = reviewSubTitle;
1602 context.review.icon = icon;
1603 context.review.onChoice = choiceCallback;
1604 context.currentPage = 0;
1605 // 1 page for title and 2 pages at the end for accept/reject
1606 context.nbPages = tagValueList->nbPairs + 3;
1607 if (reviewSubTitle) {
1608 context.nbPages++; // 1 page for subtitle page
1609 }
1610
1611 displayReviewPage(FORWARD_DIRECTION);
1612}
1613
1614#ifdef NBGL_KEYPAD
1615static void setPinCodeText(void)
1616{
1617 bool enableValidate = false;
1618 bool enableBackspace = true;
1619
1620 // pin can be validated when min digits is entered
1621 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
1622 // backspace is disabled when no digit is entered and back vallback is not provided
1623 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
1624 nbgl_layoutUpdateKeypadContent(context.keypad.layoutCtx,
1625 context.keypad.hidden,
1626 context.keypad.pinLen,
1627 (const char *) context.keypad.pinEntry);
1629 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
1630 nbgl_layoutDraw(context.keypad.layoutCtx);
1631 nbgl_refresh();
1632}
1633
1634// called when a key is touched on the keypad
1635static void keypadCallback(char touchedKey)
1636{
1637 switch (touchedKey) {
1638 case BACKSPACE_KEY:
1639 if (context.keypad.pinLen > 0) {
1640 context.keypad.pinLen--;
1641 context.keypad.pinEntry[context.keypad.pinLen] = 0;
1642 }
1643 else if (context.keypad.backCallback != NULL) {
1644 context.keypad.backCallback();
1645 break;
1646 }
1647 setPinCodeText();
1648 break;
1649
1650 case VALIDATE_KEY:
1651 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
1652 break;
1653
1654 default:
1655 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1656 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
1657 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
1658 context.keypad.pinLen++;
1659 }
1660 setPinCodeText();
1661 }
1662 break;
1663 }
1664}
1665
1666// called to create a keypad, with either hidden or visible digits
1667static void keypadGenericUseCase(const char *title,
1668 uint8_t minDigits,
1669 uint8_t maxDigits,
1670 bool shuffled,
1671 bool hidden,
1672 nbgl_pinValidCallback_t validatePinCallback,
1673 nbgl_callback_t backCallback)
1674{
1675 nbgl_layoutDescription_t layoutDescription = {0};
1676 int status = -1;
1677
1678 // reset the keypad context
1679 memset(&context, 0, sizeof(KeypadContext_t));
1680 context.type = KEYPAD_USE_CASE;
1681 context.currentPage = 0;
1682 context.nbPages = 1;
1683 context.keypad.validatePin = validatePinCallback;
1684 context.keypad.backCallback = backCallback;
1685 context.keypad.pinMinDigits = minDigits;
1686 context.keypad.pinMaxDigits = maxDigits;
1687 context.keypad.hidden = hidden;
1688 context.keypad.layoutCtx = nbgl_layoutGet(&layoutDescription);
1689
1690 // add keypad
1691 status = nbgl_layoutAddKeypad(context.keypad.layoutCtx, keypadCallback, title, shuffled);
1692 if (status < 0) {
1693 return;
1694 }
1695 context.keypad.keypadIndex = status;
1696 // add digits
1697 status = nbgl_layoutAddKeypadContent(context.keypad.layoutCtx, hidden, maxDigits, "");
1698 if (status < 0) {
1699 return;
1700 }
1701
1702 nbgl_layoutDraw(context.keypad.layoutCtx);
1703 if (context.keypad.backCallback != NULL) {
1704 // force backspace to be visible at first digit, to be used as quit
1705 nbgl_layoutUpdateKeypad(context.keypad.layoutCtx, context.keypad.keypadIndex, false, true);
1706 }
1707 nbgl_refresh();
1708}
1709#endif // NBGL_KEYPAD
1710
1711// this is the callback used when navigating in warning pages
1712static void warningNavigate(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
1713{
1714 UNUSED(stepCtx);
1715
1716 if (event == BUTTON_LEFT_PRESSED) {
1717 // only decrement page if we are not at the first page
1718 if (reviewWithWarnCtx.warningPage > 0) {
1719 reviewWithWarnCtx.warningPage--;
1720 }
1721 }
1722 else if (event == BUTTON_RIGHT_PRESSED) {
1723 // only increment page if not at last page
1724 if (reviewWithWarnCtx.warningPage < (reviewWithWarnCtx.nbWarningPages - 1)) {
1725 reviewWithWarnCtx.warningPage++;
1726 }
1727 }
1728 else if (event == BUTTON_BOTH_PRESSED) {
1729 // if at first page, double press leads to start of review
1730 if (reviewWithWarnCtx.warningPage == 0) {
1731 if (reviewWithWarnCtx.type == REVIEW_USE_CASE) {
1732 useCaseReview(reviewWithWarnCtx.type,
1733 reviewWithWarnCtx.operationType,
1734 reviewWithWarnCtx.tagValueList,
1735 reviewWithWarnCtx.icon,
1736 reviewWithWarnCtx.reviewTitle,
1737 reviewWithWarnCtx.reviewSubTitle,
1738 reviewWithWarnCtx.finishTitle,
1739 reviewWithWarnCtx.choiceCallback);
1740 }
1741 else if (reviewWithWarnCtx.type == STREAMING_START_REVIEW_USE_CASE) {
1742 displayStreamingReviewPage(FORWARD_DIRECTION);
1743 }
1744 }
1745 // if at last page, reject operation
1746 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1747 reviewWithWarnCtx.choiceCallback(false);
1748 }
1749 return;
1750 }
1751 else {
1752 return;
1753 }
1754 displayWarningStep();
1755}
1756
1757// function used to display the initial warning page when starting a "review with warning"
1758static void displayWarningStep(void)
1759{
1760 nbgl_layoutCenteredInfo_t info = {0};
1761 nbgl_stepPosition_t pos = 0;
1762 if (reviewWithWarnCtx.warningPage == 0) {
1763 // draw the main warning page
1764 info.icon = &C_icon_warning;
1765 info.text1 = "Blind signing ahead";
1766 info.text2 = "To accept risk, press both buttons";
1768 }
1769 else if (reviewWithWarnCtx.warningPage == (reviewWithWarnCtx.nbWarningPages - 1)) {
1770 getLastPageInfo(false, &info.icon, &info.text1);
1772 }
1773 info.style = BOLD_TEXT1_INFO;
1774 nbgl_stepDrawCenteredInfo(pos, warningNavigate, NULL, &info, false);
1775 nbgl_refresh();
1776}
1777
1778// function used to display the initial warning page when starting a "review with warning"
1779static void displayInitialWarning(void)
1780{
1781 // draw the main warning page
1782 reviewWithWarnCtx.warningPage = 0;
1783 reviewWithWarnCtx.nbWarningPages = 2;
1784 displayWarningStep();
1785}
1786
1787/**********************
1788 * GLOBAL FUNCTIONS
1789 **********************/
1790
1803 const nbgl_contentTagValueList_t *tagValueList,
1804 uint8_t startIndex,
1805 bool *requireSpecificDisplay)
1806{
1807 UNUSED(nbPairs);
1808 UNUSED(tagValueList);
1809 UNUSED(startIndex);
1810 *requireSpecificDisplay = true;
1811 return 1;
1812}
1813
1827 const nbgl_contentTagValueList_t *tagValueList,
1828 uint8_t startIndex,
1829 bool isSkippable,
1830 bool *requireSpecificDisplay)
1831{
1832 UNUSED(nbPairs);
1833 UNUSED(tagValueList);
1834 UNUSED(startIndex);
1835 UNUSED(isSkippable);
1836 *requireSpecificDisplay = true;
1837 return 1;
1838}
1839
1849 const nbgl_contentInfoList_t *infosList,
1850 uint8_t startIndex,
1851 bool withNav)
1852{
1853 UNUSED(nbInfos);
1854 UNUSED(infosList);
1855 UNUSED(startIndex);
1856 UNUSED(withNav);
1857 return 1;
1858}
1859
1869 const nbgl_contentSwitchesList_t *switchesList,
1870 uint8_t startIndex,
1871 bool withNav)
1872{
1873 UNUSED(nbSwitches);
1874 UNUSED(switchesList);
1875 UNUSED(startIndex);
1876 UNUSED(withNav);
1877 return 1;
1878}
1879
1889 const nbgl_contentBarsList_t *barsList,
1890 uint8_t startIndex,
1891 bool withNav)
1892{
1893 UNUSED(nbBars);
1894 UNUSED(barsList);
1895 UNUSED(startIndex);
1896 UNUSED(withNav);
1897 return 1;
1898}
1899
1909 const nbgl_contentRadioChoice_t *choicesList,
1910 uint8_t startIndex,
1911 bool withNav)
1912{
1913 UNUSED(nbChoices);
1914 UNUSED(choicesList);
1915 UNUSED(startIndex);
1916 UNUSED(withNav);
1917 return 1;
1918}
1919
1927{
1928 uint8_t nbPages = 0;
1929 uint8_t nbPairs = tagValueList->nbPairs;
1930 uint8_t nbPairsInPage;
1931 uint8_t i = 0;
1932 bool flag;
1933
1934 while (i < tagValueList->nbPairs) {
1935 // upper margin
1936 nbPairsInPage = nbgl_useCaseGetNbTagValuesInPageExt(nbPairs, tagValueList, i, false, &flag);
1937 i += nbPairsInPage;
1938 nbPairs -= nbPairsInPage;
1939 nbPages++;
1940 }
1941 return nbPages;
1942}
1943
1957void nbgl_useCaseNavigableContent(const char *title,
1958 uint8_t initPage,
1959 uint8_t nbPages,
1960 nbgl_callback_t quitCallback,
1961 nbgl_navCallback_t navCallback,
1962 nbgl_layoutTouchCallback_t controlsCallback)
1963{
1964 nbgl_pageContent_t pageContent = {0};
1965 static nbgl_content_t contentsList = {0};
1966
1967 if (initPage >= nbPages) {
1968 return;
1969 }
1970 // Use Callback to get the page content
1971 if (navCallback(initPage, &pageContent) == false) {
1972 return;
1973 }
1974 memset(&context, 0, sizeof(UseCaseContext_t));
1975 context.type = CONTENT_USE_CASE;
1976 context.content.quitCallback = quitCallback;
1977 context.content.controlsCallback = controlsCallback;
1978 context.content.genericContents.callbackCallNeeded = false;
1979 context.content.genericContents.nbContents = nbPages;
1980
1981 contentsList.type = pageContent.type;
1982 switch (pageContent.type) {
1983 case CENTERED_INFO:
1984 contentsList.content.centeredInfo = pageContent.centeredInfo;
1985 break;
1986 case INFO_BUTTON:
1987 contentsList.content.infoButton = pageContent.infoButton;
1988 break;
1989 case TAG_VALUE_LIST:
1990 contentsList.content.tagValueList = pageContent.tagValueList;
1991 break;
1992 case SWITCHES_LIST:
1993 contentsList.content.switchesList = pageContent.switchesList;
1994 break;
1995 case INFOS_LIST:
1996 contentsList.content.infosList = pageContent.infosList;
1997 break;
1998 case CHOICES_LIST:
1999 contentsList.content.choicesList = pageContent.choicesList;
2000 context.content.title = title;
2001 context.currentPage = pageContent.choicesList.initChoice;
2002 break;
2003 case BARS_LIST:
2004 contentsList.content.barsList = pageContent.barsList;
2005 context.content.title = title;
2006 break;
2007 default:
2008 break;
2009 }
2010 context.content.genericContents.contentsList = (const nbgl_content_t *) &contentsList;
2011
2012 startUseCaseContent();
2013}
2014
2029void nbgl_useCaseHomeAndSettings(const char *appName,
2030 const nbgl_icon_details_t *appIcon,
2031 const char *tagline,
2032 const uint8_t initSettingPage,
2033 const nbgl_genericContents_t *settingContents,
2034 const nbgl_contentInfoList_t *infosList,
2035 const nbgl_homeAction_t *action,
2036 nbgl_callback_t quitCallback)
2037{
2038 memset(&context, 0, sizeof(UseCaseContext_t));
2039 context.home.appName = appName;
2040 context.home.appIcon = appIcon;
2041 context.home.tagline = tagline;
2042 context.home.settingContents = PIC(settingContents);
2043 context.home.infosList = PIC(infosList);
2044 context.home.homeAction = action;
2045 context.home.quitCallback = quitCallback;
2046
2047 if (initSettingPage != INIT_HOME_PAGE) {
2048 startUseCaseSettingsAtPage(initSettingPage);
2049 }
2050 else {
2051 startUseCaseHome();
2052 }
2053}
2054
2067void nbgl_useCaseGenericSettings(const char *appName,
2068 uint8_t initPage,
2069 const nbgl_genericContents_t *settingContents,
2070 const nbgl_contentInfoList_t *infosList,
2071 nbgl_callback_t quitCallback)
2072{
2073 memset(&context, 0, sizeof(UseCaseContext_t));
2074 context.type = GENERIC_SETTINGS;
2075 context.home.appName = appName;
2076 context.home.settingContents = PIC(settingContents);
2077 context.home.infosList = PIC(infosList);
2078 context.home.quitCallback = quitCallback;
2079
2080 startUseCaseSettingsAtPage(initPage);
2081}
2082
2094void nbgl_useCaseGenericConfiguration(const char *title,
2095 uint8_t initPage,
2096 const nbgl_genericContents_t *contents,
2097 nbgl_callback_t quitCallback)
2098{
2099 nbgl_useCaseGenericSettings(title, initPage, contents, NULL, quitCallback);
2100}
2101
2116void nbgl_useCaseReview(nbgl_operationType_t operationType,
2117 const nbgl_contentTagValueList_t *tagValueList,
2118 const nbgl_icon_details_t *icon,
2119 const char *reviewTitle,
2120 const char *reviewSubTitle,
2121 const char *finishTitle,
2122 nbgl_choiceCallback_t choiceCallback)
2123{
2124 useCaseReview(REVIEW_USE_CASE,
2125 operationType,
2126 tagValueList,
2127 icon,
2128 reviewTitle,
2129 reviewSubTitle,
2130 finishTitle,
2131 choiceCallback);
2132}
2133
2157 const nbgl_contentTagValueList_t *tagValueList,
2158 const nbgl_icon_details_t *icon,
2159 const char *reviewTitle,
2160 const char *reviewSubTitle,
2161 const char *finishTitle,
2162 const nbgl_tipBox_t *tipBox,
2163 const nbgl_warning_t *warning,
2164 nbgl_choiceCallback_t choiceCallback)
2165{
2166 UNUSED(tipBox);
2167 ContextType_t type = REVIEW_USE_CASE;
2168
2169 // if no warning at all, it's a simple review
2170 if ((warning == NULL)
2171 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2172 && (warning->reviewDetails == NULL))) {
2173 useCaseReview(type,
2174 operationType,
2175 tagValueList,
2176 icon,
2177 reviewTitle,
2178 reviewSubTitle,
2179 finishTitle,
2180 choiceCallback);
2181 return;
2182 }
2183 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2184 operationType |= NO_THREAT_OPERATION;
2185 }
2186 else {
2187 operationType |= RISKY_OPERATION;
2188 }
2189
2190 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2191 reviewWithWarnCtx.type = type;
2192 reviewWithWarnCtx.operationType = operationType;
2193 reviewWithWarnCtx.tagValueList = tagValueList;
2194 reviewWithWarnCtx.icon = icon;
2195 reviewWithWarnCtx.reviewTitle = reviewTitle;
2196 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2197 reviewWithWarnCtx.finishTitle = finishTitle;
2198 reviewWithWarnCtx.warning = warning;
2199 reviewWithWarnCtx.choiceCallback = choiceCallback;
2200
2201 // display the initial warning only of a risk/threat or blind signing
2202 if (!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2203 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2204 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN))) {
2205 useCaseReview(type,
2206 operationType,
2207 tagValueList,
2208 icon,
2209 reviewTitle,
2210 reviewSubTitle,
2211 finishTitle,
2212 choiceCallback);
2213 return;
2214 }
2215 displayInitialWarning();
2216}
2217
2238 const nbgl_contentTagValueList_t *tagValueList,
2239 const nbgl_icon_details_t *icon,
2240 const char *reviewTitle,
2241 const char *reviewSubTitle,
2242 const char *finishTitle,
2243 const nbgl_tipBox_t *dummy,
2244 nbgl_choiceCallback_t choiceCallback)
2245{
2246 nbgl_useCaseAdvancedReview(operationType,
2247 tagValueList,
2248 icon,
2249 reviewTitle,
2250 reviewSubTitle,
2251 finishTitle,
2252 dummy,
2253 &blindSigningWarning,
2254 choiceCallback);
2255}
2256
2272 const nbgl_contentTagValueList_t *tagValueList,
2273 const nbgl_icon_details_t *icon,
2274 const char *reviewTitle,
2275 const char *reviewSubTitle,
2276 const char *finishTitle,
2277 nbgl_choiceCallback_t choiceCallback)
2278{
2279 nbgl_useCaseReview(operationType,
2280 tagValueList,
2281 icon,
2282 reviewTitle,
2283 reviewSubTitle,
2284 finishTitle,
2285 choiceCallback);
2286}
2287
2304void nbgl_useCaseAddressReview(const char *address,
2305 const nbgl_contentTagValueList_t *additionalTagValueList,
2306 const nbgl_icon_details_t *icon,
2307 const char *reviewTitle,
2308 const char *reviewSubTitle,
2309 nbgl_choiceCallback_t choiceCallback)
2310{
2311 memset(&context, 0, sizeof(UseCaseContext_t));
2312 context.type = ADDRESS_REVIEW_USE_CASE;
2313 context.review.address = address;
2314 context.review.reviewTitle = reviewTitle;
2315 context.review.reviewSubTitle = reviewSubTitle;
2316 context.review.icon = icon;
2317 context.review.onChoice = choiceCallback;
2318 context.currentPage = 0;
2319 // + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
2320 context.nbPages = 4;
2321 if (additionalTagValueList) {
2322 context.review.tagValueList = PIC(additionalTagValueList);
2323 context.nbPages += additionalTagValueList->nbPairs;
2324 }
2325
2326 displayReviewPage(FORWARD_DIRECTION);
2327}
2328
2338 const char *rejectText,
2339 nbgl_callback_t rejectCallback)
2340{
2341 memset(&context, 0, sizeof(UseCaseContext_t));
2342 context.type = GENERIC_REVIEW_USE_CASE;
2343 context.content.rejectText = rejectText;
2344 context.content.quitCallback = rejectCallback;
2345 context.content.genericContents.nbContents = contents->nbContents;
2346 context.content.genericContents.callbackCallNeeded = contents->callbackCallNeeded;
2347 if (contents->callbackCallNeeded) {
2348 context.content.genericContents.contentGetterCallback = contents->contentGetterCallback;
2349 }
2350 else {
2351 context.content.genericContents.contentsList = PIC(contents->contentsList);
2352 }
2353
2354 startUseCaseContent();
2355}
2356
2364void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
2365{
2366 UNUSED(isSuccess);
2367 memset(&context, 0, sizeof(UseCaseContext_t));
2368 context.type = STATUS_USE_CASE;
2369 context.stepCallback = quitCallback;
2370 context.currentPage = 0;
2371 context.nbPages = 1;
2372
2373 drawStep(SINGLE_STEP, NULL, message, NULL, statusButtonCallback, false, NO_FORCED_TYPE);
2374}
2375
2383 nbgl_callback_t quitCallback)
2384{
2385 const char *msg;
2386 bool isSuccess;
2387 switch (reviewStatusType) {
2389 msg = "Operation signed";
2390 isSuccess = true;
2391 break;
2393 msg = "Operation rejected";
2394 isSuccess = false;
2395 break;
2397 msg = "Transaction signed";
2398 isSuccess = true;
2399 break;
2401 msg = "Transaction rejected";
2402 isSuccess = false;
2403 break;
2405 msg = "Message signed";
2406 isSuccess = true;
2407 break;
2409 msg = "Message rejected";
2410 isSuccess = false;
2411 break;
2413 msg = "Address verified";
2414 isSuccess = true;
2415 break;
2417 msg = "Address verification cancelled";
2418 isSuccess = false;
2419 break;
2420 default:
2421 return;
2422 }
2423 nbgl_useCaseStatus(msg, isSuccess, quitCallback);
2424}
2425
2439 const nbgl_icon_details_t *icon,
2440 const char *reviewTitle,
2441 const char *reviewSubTitle,
2442 nbgl_choiceCallback_t choiceCallback)
2443{
2444 memset(&context, 0, sizeof(UseCaseContext_t));
2445 context.type = STREAMING_START_REVIEW_USE_CASE;
2446 context.operationType = operationType;
2447 context.review.reviewTitle = reviewTitle;
2448 context.review.reviewSubTitle = reviewSubTitle;
2449 context.review.icon = icon;
2450 context.review.onChoice = choiceCallback;
2451 context.currentPage = 0;
2452 context.nbPages = 2; // Start page + trick for review continue
2453
2454 displayStreamingReviewPage(FORWARD_DIRECTION);
2455}
2456
2471 const nbgl_icon_details_t *icon,
2472 const char *reviewTitle,
2473 const char *reviewSubTitle,
2474 nbgl_choiceCallback_t choiceCallback)
2475{
2477 operationType, icon, reviewTitle, reviewSubTitle, &blindSigningWarning, choiceCallback);
2478}
2479
2496 const nbgl_icon_details_t *icon,
2497 const char *reviewTitle,
2498 const char *reviewSubTitle,
2499 const nbgl_warning_t *warning,
2500 nbgl_choiceCallback_t choiceCallback)
2501{
2502 memset(&context, 0, sizeof(UseCaseContext_t));
2503 context.type = STREAMING_START_REVIEW_USE_CASE;
2504 context.operationType = operationType;
2505 context.review.reviewTitle = reviewTitle;
2506 context.review.reviewSubTitle = reviewSubTitle;
2507 context.review.icon = icon;
2508 context.review.onChoice = choiceCallback;
2509 context.currentPage = 0;
2510 context.nbPages = 2; // Start page + trick for review continue
2511
2512 // if no warning at all, it's a simple review
2513 if ((warning == NULL)
2514 || ((warning->predefinedSet == 0) && (warning->introDetails == NULL)
2515 && (warning->reviewDetails == NULL))) {
2516 displayStreamingReviewPage(FORWARD_DIRECTION);
2517 return;
2518 }
2519 if (warning->predefinedSet == (1 << W3C_NO_THREAT_WARN)) {
2520 operationType |= NO_THREAT_OPERATION;
2521 }
2522 else {
2523 operationType |= RISKY_OPERATION;
2524 }
2525 memset(&reviewWithWarnCtx, 0, sizeof(reviewWithWarnCtx));
2526
2527 reviewWithWarnCtx.type = context.type;
2528 reviewWithWarnCtx.operationType = operationType;
2529 reviewWithWarnCtx.icon = icon;
2530 reviewWithWarnCtx.reviewTitle = reviewTitle;
2531 reviewWithWarnCtx.reviewSubTitle = reviewSubTitle;
2532 reviewWithWarnCtx.choiceCallback = choiceCallback;
2533 reviewWithWarnCtx.warning = warning;
2534
2535 // display the initial warning only of a risk/threat or blind signing
2536 if (!(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_THREAT_DETECTED_WARN))
2537 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << W3C_RISK_DETECTED_WARN))
2538 && !(reviewWithWarnCtx.warning->predefinedSet & (1 << BLIND_SIGNING_WARN))) {
2539 displayStreamingReviewPage(FORWARD_DIRECTION);
2540 return;
2541 }
2542 displayInitialWarning();
2543}
2544
2559 nbgl_choiceCallback_t choiceCallback,
2560 nbgl_callback_t skipCallback)
2561{
2562 uint8_t curNbDataSets = context.review.nbDataSets;
2563 nbgl_operationType_t operationType = context.operationType;
2564
2565 memset(&context, 0, sizeof(UseCaseContext_t));
2566 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2567 context.operationType = operationType;
2568 context.review.tagValueList = tagValueList;
2569 context.review.onChoice = choiceCallback;
2570 context.currentPage = 0;
2571 context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
2572 context.review.skipCallback = skipCallback;
2573 context.review.nbDataSets = curNbDataSets + 1;
2574
2575 displayStreamingReviewPage(FORWARD_DIRECTION);
2576}
2577
2589 nbgl_choiceCallback_t choiceCallback)
2590{
2591 nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL);
2592}
2593
2594void nbgl_useCaseReviewStreamingFinish(const char *finishTitle,
2595 nbgl_choiceCallback_t choiceCallback)
2596{
2597 nbgl_operationType_t operationType = context.operationType;
2598 UNUSED(finishTitle); // TODO dedicated screen for it?
2599
2600 memset(&context, 0, sizeof(UseCaseContext_t));
2601 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
2602 context.operationType = operationType;
2603 context.review.onChoice = choiceCallback;
2604 context.currentPage = 0;
2605 context.nbPages = 2; // 2 pages at the end for accept/reject
2606
2607 displayStreamingReviewPage(FORWARD_DIRECTION);
2608}
2609
2615void nbgl_useCaseSpinner(const char *text)
2616{
2617 memset(&context, 0, sizeof(UseCaseContext_t));
2618 context.type = SPINNER_USE_CASE;
2619 context.currentPage = 0;
2620 context.nbPages = 1;
2621
2622 displaySpinner(text);
2623}
2624
2626 const char *message,
2627 const char *subMessage,
2628 const char *confirmText,
2629 const char *cancelText,
2630 nbgl_choiceCallback_t callback)
2631{
2632 memset(&context, 0, sizeof(UseCaseContext_t));
2633 context.type = CHOICE_USE_CASE;
2634 context.choice.icon = icon;
2635 context.choice.message = message;
2636 context.choice.subMessage = subMessage;
2637 context.choice.confirmText = confirmText;
2638 context.choice.cancelText = cancelText;
2639 context.choice.onChoice = callback;
2640 context.currentPage = 0;
2641 context.nbPages = 1 + 1 + 2; // 2 pages at the end for confirm/cancel
2642
2643 displayChoicePage(FORWARD_DIRECTION);
2644};
2645
2659void nbgl_useCaseConfirm(const char *message,
2660 const char *subMessage,
2661 const char *confirmText,
2662 const char *cancelText,
2663 nbgl_callback_t callback)
2664{
2665 memset(&context, 0, sizeof(UseCaseContext_t));
2666 context.type = CONFIRM_USE_CASE;
2667 context.confirm.message = message;
2668 context.confirm.subMessage = subMessage;
2669 context.confirm.confirmText = confirmText;
2670 context.confirm.cancelText = cancelText;
2671 context.confirm.onConfirm = callback;
2672 context.currentPage = 0;
2673 context.nbPages = 1 + 2; // 2 pages at the end for confirm/cancel
2674
2675 displayConfirm(FORWARD_DIRECTION);
2676}
2677
2678#ifdef NBGL_KEYPAD
2696void nbgl_useCaseKeypadDigits(const char *title,
2697 uint8_t minDigits,
2698 uint8_t maxDigits,
2699 bool shuffled,
2700 nbgl_pinValidCallback_t validatePinCallback,
2701 nbgl_callback_t backCallback)
2702{
2703 keypadGenericUseCase(
2704 title, minDigits, maxDigits, shuffled, false, validatePinCallback, backCallback);
2705}
2706
2725void nbgl_useCaseKeypadPIN(const char *title,
2726 uint8_t minDigits,
2727 uint8_t maxDigits,
2728 bool shuffled,
2729 nbgl_pinValidCallback_t validatePinCallback,
2730 nbgl_callback_t backCallback)
2731{
2732 keypadGenericUseCase(
2733 title, minDigits, maxDigits, shuffled, true, validatePinCallback, backCallback);
2734}
2735#endif // NBGL_KEYPAD
2736
2737#endif // HAVE_SE_TOUCH
2738#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
@ 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:1650
nbgl_buttonEvent_t
Definition nbgl_obj.h:207
@ BUTTON_BOTH_PRESSED
Sent when both buttons are released.
Definition nbgl_obj.h:214
@ BUTTON_LEFT_PRESSED
Sent when Left button is released.
Definition nbgl_obj.h:208
@ BUTTON_RIGHT_PRESSED
Send when Right button is released.
Definition nbgl_obj.h:209
#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 contains nbgl_layoutNavIndication_t in its LSBs and direction in its MSB (using FORWARD_DIR...
Definition nbgl_step.h:80
@ 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
nbgl_step_t nbgl_stepDrawMenuList(nbgl_stepMenuListCallback_t onActionCallback, nbgl_screenTickerConfiguration_t *ticker, nbgl_layoutMenuList_t *list, bool modal)
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
Definition nbgl_step.h:73
nbgl_state_t
to represent a boolean state.
Definition nbgl_types.h:181
@ ON_STATE
Definition nbgl_types.h:183
@ OFF_STATE
Definition nbgl_types.h:182
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.
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)
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_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)
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 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 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
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
unsigned char uint8_t
Definition usbd_conf.h:53
signed char int8_t
Definition usbd_conf.h:49