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
26/**********************
27 * TYPEDEFS
28 **********************/
29
30typedef struct ReviewContext_s {
31 nbgl_choiceCallback_t onChoice;
32 const nbgl_contentTagValueList_t *tagValueList;
33 const nbgl_icon_details_t *icon;
34 const char *reviewTitle;
35 const char *reviewSubTitle;
36 const char *address; // for address confirmation review
37 nbgl_callback_t skipCallback; // callback provided by used
38 bool dataDisplay; // set to true if the current step is a tag/value pair
39 uint8_t dataDirection; // used to know whether the skip page is reached from back or forward
40} ReviewContext_t;
41
42typedef struct ChoiceContext_s {
43 const nbgl_icon_details_t *icon;
44 const char *message;
45 const char *subMessage;
46 const char *confirmText;
47 const char *cancelText;
48 nbgl_choiceCallback_t onChoice;
49} ChoiceContext_t;
50
51typedef struct ConfirmContext_s {
52 const char *message;
53 const char *subMessage;
54 const char *confirmText;
55 const char *cancelText;
56 nbgl_callback_t onConfirm;
57 nbgl_step_t currentStep;
58} ConfirmContext_t;
59
60typedef struct ContentContext_s {
61 const char *title; // For CHOICES_LIST /BARS_LIST
62 nbgl_genericContents_t genericContents;
63 const char *rejectText;
64 nbgl_layoutTouchCallback_t controlsCallback;
65 nbgl_callback_t quitCallback;
66} ContentContext_t;
67
68typedef struct HomeContext_s {
69 const char *appName;
70 const nbgl_icon_details_t *appIcon;
71 const char *tagline;
72 const nbgl_genericContents_t *settingContents;
73 const nbgl_contentInfoList_t *infosList;
74 const nbgl_homeAction_t *homeAction;
75 nbgl_callback_t quitCallback;
76} HomeContext_t;
77
78#ifdef NBGL_KEYPAD
79typedef struct KeypadContext_s {
80 uint8_t pinEntry[8];
81 uint8_t pinLen;
82 uint8_t pinMinDigits;
83 uint8_t pinMaxDigits;
84 nbgl_layout_t *layoutCtx;
85 bool hidden;
86 uint8_t keypadIndex;
87 nbgl_pinValidCallback_t validatePin;
88 nbgl_callback_t backCallback;
89} KeypadContext_t;
90#endif
91
92typedef enum {
93 NONE_USE_CASE,
94 SPINNER_USE_CASE,
95 REVIEW_USE_CASE,
96 GENERIC_REVIEW_USE_CASE,
97 REVIEW_BLIND_SIGN_USE_CASE,
98 ADDRESS_REVIEW_USE_CASE,
99 STREAMING_BLIND_SIGN_START_REVIEW_USE_CASE,
100 STREAMING_START_REVIEW_USE_CASE,
101 STREAMING_CONTINUE_REVIEW_USE_CASE,
102 STREAMING_FINISH_REVIEW_USE_CASE,
103 CHOICE_USE_CASE,
104 STATUS_USE_CASE,
105 CONFIRM_USE_CASE,
106 KEYPAD_USE_CASE,
107 HOME_USE_CASE,
108 INFO_USE_CASE,
109 SETTINGS_USE_CASE,
110 GENERIC_SETTINGS,
111 CONTENT_USE_CASE,
112} ContextType_t;
113
114typedef struct UseCaseContext_s {
115 ContextType_t type;
116 uint8_t nbPages;
117 int8_t currentPage;
119 stepCallback;
120 union {
121 ReviewContext_t review;
122 ChoiceContext_t choice;
123 ConfirmContext_t confirm;
124 HomeContext_t home;
125 ContentContext_t content;
126#ifdef NBGL_KEYPAD
127 KeypadContext_t keypad;
128#endif
129 };
130} UseCaseContext_t;
131
132/**********************
133 * STATIC VARIABLES
134 **********************/
135static UseCaseContext_t context;
136
137/**********************
138 * STATIC FUNCTIONS
139 **********************/
140static void displayReviewPage(nbgl_stepPosition_t pos);
141static void displayStreamingReviewPage(nbgl_stepPosition_t pos);
142static void displayHomePage(nbgl_stepPosition_t pos);
143static void displayInfoPage(nbgl_stepPosition_t pos);
144static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state);
145static void displayChoicePage(nbgl_stepPosition_t pos);
146static void displayConfirm(nbgl_stepPosition_t pos);
147static void displayContent(nbgl_stepPosition_t pos, bool toogle_state);
148static void displaySpinner(const char *text);
149
150static void startUseCaseHome(void);
151static void startUseCaseInfo(void);
152static void startUseCaseSettings(void);
153static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
154static void startUseCaseContent(void);
155
156static void statusTickerCallback(void);
157
158// Simple helper to get the number of elements inside a nbgl_content_t
159static uint8_t getContentNbElement(const nbgl_content_t *content)
160{
161 switch (content->type) {
162 case CENTERED_INFO:
163 return 1;
164 case INFO_BUTTON:
165 return 1;
166 case TAG_VALUE_LIST:
167 return content->content.tagValueList.nbPairs;
168 case SWITCHES_LIST:
169 return content->content.switchesList.nbSwitches;
170 case INFOS_LIST:
171 return content->content.infosList.nbInfos;
172 case CHOICES_LIST:
173 return content->content.choicesList.nbChoices;
174 case BARS_LIST:
175 return content->content.barsList.nbBars;
176 default:
177 return 0;
178 }
179}
180
181// Helper to retrieve the content inside a nbgl_genericContents_t using
182// either the contentsList or using the contentGetterCallback
183static const nbgl_content_t *getContentAtIdx(const nbgl_genericContents_t *genericContents,
184 int8_t contentIdx,
185 nbgl_content_t *content)
186{
187 if (contentIdx < 0 || contentIdx >= genericContents->nbContents) {
188 LOG_DEBUG(USE_CASE_LOGGER, "No content available at %d\n", contentIdx);
189 return NULL;
190 }
191
192 if (genericContents->callbackCallNeeded) {
193 if (content == NULL) {
194 LOG_DEBUG(USE_CASE_LOGGER, "Invalid content variable\n");
195 return NULL;
196 }
197 // Retrieve content through callback, but first memset the content.
198 memset(content, 0, sizeof(nbgl_content_t));
199 genericContents->contentGetterCallback(contentIdx, content);
200 return content;
201 }
202 else {
203 // Retrieve content through list
204 return PIC(&genericContents->contentsList[contentIdx]);
205 }
206}
207
208// Helper to retrieve the content inside a nbgl_genericContents_t using
209// either the contentsList or using the contentGetterCallback
210static const nbgl_content_t *getContentElemAtIdx(uint8_t elemIdx,
211 uint8_t *elemContentIdx,
212 nbgl_content_t *content)
213{
214 const nbgl_genericContents_t *genericContents = NULL;
215 const nbgl_content_t *p_content = NULL;
216 uint8_t nbPages = 0;
217 uint8_t elemNbPages = 0;
218
219 switch (context.type) {
220 case SETTINGS_USE_CASE:
221 case HOME_USE_CASE:
222 case GENERIC_SETTINGS:
223 genericContents = context.home.settingContents;
224 break;
225 case CONTENT_USE_CASE:
226 case GENERIC_REVIEW_USE_CASE:
227 genericContents = &context.content.genericContents;
228 break;
229 default:
230 return NULL;
231 }
232 for (int i = 0; i < genericContents->nbContents; i++) {
233 p_content = getContentAtIdx(genericContents, i, content);
234 elemNbPages = getContentNbElement(p_content);
235 if (nbPages + elemNbPages > elemIdx) {
236 *elemContentIdx = context.currentPage - nbPages;
237 break;
238 }
239 nbPages += elemNbPages;
240 }
241
242 return p_content;
243}
244
245static const char *getChoiceName(uint8_t choiceIndex)
246{
247 uint8_t elemIdx;
248 uint8_t nbValues;
249 const nbgl_content_t *p_content = NULL;
250 nbgl_content_t content = {0};
251 nbgl_contentRadioChoice_t *contentChoices = NULL;
252 nbgl_contentBarsList_t *contentBars = NULL;
253 char **names = NULL;
254
255 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
256 if (p_content == NULL) {
257 return NULL;
258 }
259 switch (p_content->type) {
260 case CHOICES_LIST:
261 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
262 names = (char **) PIC(contentChoices->names);
263 nbValues = contentChoices->nbChoices;
264 break;
265 case BARS_LIST:
266 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
267 names = (char **) PIC(contentBars->barTexts);
268 nbValues = contentBars->nbBars;
269 break;
270 default:
271 // Not supported as vertical MenuList
272 return NULL;
273 }
274 if (choiceIndex >= nbValues) {
275 // Last item is always "Back" button
276 return "Back";
277 }
278 return (const char *) PIC(names[choiceIndex]);
279}
280
281static void onChoiceSelected(uint8_t choiceIndex)
282{
283 uint8_t elemIdx;
284 uint8_t token = 255;
285 const nbgl_content_t *p_content = NULL;
286 nbgl_content_t content = {0};
287 nbgl_contentRadioChoice_t *contentChoices = NULL;
288 nbgl_contentBarsList_t *contentBars = NULL;
289
290 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
291 if (p_content == NULL) {
292 return;
293 }
294 switch (p_content->type) {
295 case CHOICES_LIST:
296 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
297 if (choiceIndex < contentChoices->nbChoices) {
298 token = contentChoices->token;
299 }
300 break;
301 case BARS_LIST:
302 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
303 if (choiceIndex < contentBars->nbBars) {
304 token = contentBars->tokens[choiceIndex];
305 }
306 break;
307 default:
308 // Not supported as vertical MenuList
309 break;
310 }
311 if ((token != 255) && (context.content.controlsCallback != NULL)) {
312 context.content.controlsCallback(token, 0);
313 }
314 else if (context.content.quitCallback != NULL) {
315 context.content.quitCallback();
316 }
317}
318
319static void getPairData(const nbgl_contentTagValueList_t *tagValueList,
320 uint8_t index,
321 const char **item,
322 const char **value)
323{
324 const nbgl_contentTagValue_t *pair;
325
326 if (tagValueList->pairs != NULL) {
327 pair = PIC(&tagValueList->pairs[index]);
328 }
329 else {
330 pair = PIC(tagValueList->callback(index));
331 }
332 *item = pair->item;
333 *value = pair->value;
334}
335
336static void onReviewAccept(void)
337{
338 if (context.review.onChoice) {
339 context.review.onChoice(true);
340 }
341}
342
343static void onReviewReject(void)
344{
345 if (context.review.onChoice) {
346 context.review.onChoice(false);
347 }
348}
349
350static void onChoiceAccept(void)
351{
352 if (context.choice.onChoice) {
353 context.choice.onChoice(true);
354 }
355}
356
357static void onChoiceReject(void)
358{
359 if (context.choice.onChoice) {
360 context.choice.onChoice(false);
361 }
362}
363
364static void onConfirmAccept(void)
365{
366 if (context.confirm.currentStep) {
367 nbgl_stepRelease(context.confirm.currentStep);
368 }
369 if (context.confirm.onConfirm) {
370 context.confirm.onConfirm();
371 }
372}
373
374static void onConfirmReject(void)
375{
376 if (context.confirm.currentStep) {
377 nbgl_stepRelease(context.confirm.currentStep);
379 nbgl_refresh();
380 }
381}
382
383static void onSwitchAction(void)
384{
385 const nbgl_contentSwitch_t *contentSwitch = NULL;
386 const nbgl_content_t *p_content = NULL;
387 nbgl_content_t content = {0};
388 uint8_t elemIdx;
389
390 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
391 if ((p_content == NULL) || (p_content->type != SWITCHES_LIST)) {
392 return;
393 }
394 contentSwitch
395 = &((const nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
396 switch (context.type) {
397 case SETTINGS_USE_CASE:
398 case HOME_USE_CASE:
399 case GENERIC_SETTINGS:
400 displaySettingsPage(FORWARD_DIRECTION, true);
401 break;
402 case CONTENT_USE_CASE:
403 case GENERIC_REVIEW_USE_CASE:
404 displayContent(FORWARD_DIRECTION, true);
405 break;
406 default:
407 break;
408 }
409 if (p_content->contentActionCallback != NULL) {
410 nbgl_contentActionCallback_t actionCallback = PIC(p_content->contentActionCallback);
411 actionCallback(contentSwitch->token, 0, context.currentPage);
412 }
413 else if (context.content.controlsCallback != NULL) {
414 context.content.controlsCallback(contentSwitch->token, 0);
415 }
416}
417
418static void drawStep(nbgl_stepPosition_t pos,
419 const nbgl_icon_details_t *icon,
420 const char *txt,
421 const char *subTxt,
422 nbgl_stepButtonCallback_t onActionCallback,
423 bool modal)
424{
425 uint8_t elemIdx;
426 nbgl_step_t newStep = NULL;
427 const nbgl_content_t *p_content = NULL;
428 nbgl_content_t content = {0};
429 nbgl_contentRadioChoice_t *contentChoices = NULL;
430 nbgl_contentBarsList_t *contentBars = NULL;
431 nbgl_screenTickerConfiguration_t *p_ticker = NULL;
432 nbgl_layoutMenuList_t list = {0};
434 .tickerCallback = PIC(statusTickerCallback),
435 .tickerIntervale = 0, // not periodic
436 .tickerValue = 3000 // 3 seconds
437 };
438
439 pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
440
441 if ((context.type == STATUS_USE_CASE) || (context.type == SPINNER_USE_CASE)) {
442 p_ticker = &ticker;
443 }
444 if ((context.type == CONFIRM_USE_CASE) && (context.confirm.currentStep != NULL)) {
445 nbgl_stepRelease(context.confirm.currentStep);
446 }
447
448 if (txt == NULL) {
449 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
450 if (p_content) {
451 switch (p_content->type) {
452 case CHOICES_LIST:
453 contentChoices
454 = ((nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList));
455 list.nbChoices = contentChoices->nbChoices + 1; // For Back button
456 list.selectedChoice = contentChoices->initChoice;
457 list.callback = getChoiceName;
458 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
459 break;
460 case BARS_LIST:
461 contentBars = ((nbgl_contentBarsList_t *) PIC(&p_content->content.barsList));
462 list.nbChoices = contentBars->nbBars + 1; // For Back button
463 list.selectedChoice = 0;
464 list.callback = getChoiceName;
465 newStep = nbgl_stepDrawMenuList(onChoiceSelected, p_ticker, &list, modal);
466 break;
467 default:
468 // Not supported as vertical MenuList
469 break;
470 }
471 }
472 }
473 else if (icon == NULL) {
474 newStep = nbgl_stepDrawText(
475 pos, onActionCallback, p_ticker, txt, subTxt, BOLD_TEXT1_INFO, modal);
476 }
477 else {
479 info.icon = icon;
480 info.text1 = txt;
481 info.text2 = subTxt;
482 info.onTop = false;
483 info.style = BOLD_TEXT1_INFO;
484 newStep = nbgl_stepDrawCenteredInfo(pos, onActionCallback, p_ticker, &info, modal);
485 }
486 if (context.type == CONFIRM_USE_CASE) {
487 context.confirm.currentStep = newStep;
488 }
489}
490
491static bool buttonGenericCallback(nbgl_buttonEvent_t event, nbgl_stepPosition_t *pos)
492{
493 uint8_t elemIdx;
494 uint8_t token = 0;
495 uint8_t index = 0;
496 const nbgl_content_t *p_content = NULL;
497 nbgl_content_t content = {0};
498
499 if (event == BUTTON_LEFT_PRESSED) {
500 if (context.currentPage > 0) {
501 context.currentPage--;
502 }
503 else {
504 // Drop the event
505 return false;
506 }
507 *pos = BACKWARD_DIRECTION;
508 }
509 else if (event == BUTTON_RIGHT_PRESSED) {
510 if (context.currentPage < (int) (context.nbPages - 1)) {
511 context.currentPage++;
512 }
513 else {
514 // Drop the event
515 return false;
516 }
517 *pos = FORWARD_DIRECTION;
518 }
519 else {
520 if (event == BUTTON_BOTH_PRESSED) {
521 if (context.stepCallback != NULL) {
522 context.stepCallback();
523 }
524 else if ((context.type == CONTENT_USE_CASE)
525 || (context.type == GENERIC_REVIEW_USE_CASE)) {
526 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
527 if (p_content != NULL) {
528 switch (p_content->type) {
529 case CENTERED_INFO:
530 // No associated callback
531 return false;
532 case INFO_BUTTON:
533 token = p_content->content.infoButton.buttonToken;
534 break;
535 case SWITCHES_LIST:
536 token = p_content->content.switchesList.switches->token;
537 break;
538 case BARS_LIST:
539 token = p_content->content.barsList.tokens[context.currentPage];
540 break;
541 case CHOICES_LIST:
542 token = p_content->content.choicesList.token;
543 index = context.currentPage;
544 break;
545 default:
546 break;
547 }
548
549 if ((p_content) && (p_content->contentActionCallback != NULL)) {
550 p_content->contentActionCallback(token, 0, context.currentPage);
551 }
552 else if (context.content.controlsCallback != NULL) {
553 context.content.controlsCallback(token, index);
554 }
555 }
556 }
557 }
558 return false;
559 }
560 return true;
561}
562
563static void reviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
564{
565 UNUSED(stepCtx);
567
568 if (!buttonGenericCallback(event, &pos)) {
569 return;
570 }
571
572 displayReviewPage(pos);
573}
574
575// this is the callback used when button action on the "skip" page
576static void buttonSkipCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
577{
578 UNUSED(stepCtx);
580
581 if (event == BUTTON_LEFT_PRESSED) {
582 if ((context.review.dataDirection == BACKWARD_DIRECTION) && (context.currentPage > 0)) {
583 context.currentPage--;
584 }
585 pos = BACKWARD_DIRECTION;
586 }
587 else if (event == BUTTON_RIGHT_PRESSED) {
588 if ((context.review.dataDirection == FORWARD_DIRECTION)
589 && (context.currentPage < (int) (context.nbPages - 1))) {
590 context.currentPage++;
591 }
592 pos = FORWARD_DIRECTION;
593 }
594 else if (event == BUTTON_BOTH_PRESSED) {
595 context.review.skipCallback();
596 return;
597 }
598 else {
599 return;
600 }
601 displayStreamingReviewPage(pos);
602}
603
604static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
605{
607 UNUSED(stepCtx);
608
609 // if skippable, draw an intermediate page
610 if ((context.review.skipCallback != NULL) && (context.review.dataDisplay == true)) {
611 if (event == BUTTON_LEFT_PRESSED) {
612 context.review.dataDirection = BACKWARD_DIRECTION;
613 }
614 else if (event == BUTTON_RIGHT_PRESSED) {
615 context.review.dataDirection = FORWARD_DIRECTION;
616 }
617 else {
618 return;
619 }
620 // this is not a tag/value
621 context.review.dataDisplay = false;
623 buttonSkipCallback,
624 NULL,
625 "Press right to continue message.\nDouble-press to skip",
626 NULL,
627 REGULAR_INFO,
628 false);
629 nbgl_refresh();
630 return;
631 }
632 if (!buttonGenericCallback(event, &pos)) {
633 return;
634 }
635
636 displayStreamingReviewPage(pos);
637}
638
639static void settingsCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
640{
641 UNUSED(stepCtx);
643
644 if (!buttonGenericCallback(event, &pos)) {
645 return;
646 }
647
648 displaySettingsPage(pos, false);
649}
650
651static void infoCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
652{
653 UNUSED(stepCtx);
655
656 if (!buttonGenericCallback(event, &pos)) {
657 return;
658 }
659
660 displayInfoPage(pos);
661}
662
663static void homeCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
664{
665 UNUSED(stepCtx);
667
668 if (!buttonGenericCallback(event, &pos)) {
669 return;
670 }
671
672 displayHomePage(pos);
673}
674
675static void genericChoiceCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
676{
677 UNUSED(stepCtx);
679
680 if (!buttonGenericCallback(event, &pos)) {
681 return;
682 }
683
684 displayChoicePage(pos);
685}
686
687static void genericConfirmCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
688{
689 UNUSED(stepCtx);
691
692 if (!buttonGenericCallback(event, &pos)) {
693 return;
694 }
695
696 displayConfirm(pos);
697}
698
699static void statusButtonCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
700{
701 UNUSED(stepCtx);
702 if (event == BUTTON_BOTH_PRESSED) {
703 if (context.stepCallback != NULL) {
704 context.stepCallback();
705 }
706 }
707}
708
709static void contentCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
710{
711 UNUSED(stepCtx);
713
714 if (!buttonGenericCallback(event, &pos)) {
715 return;
716 }
717
718 displayContent(pos, false);
719}
720
721// callback used for timeout
722static void statusTickerCallback(void)
723{
724 if (context.stepCallback != NULL) {
725 context.stepCallback();
726 }
727}
728
729// function used to display the current page in review
730static void displayReviewPage(nbgl_stepPosition_t pos)
731{
732 uint8_t reviewPages = 0;
733 uint8_t finalPages = 0;
734 uint8_t pairIndex = 0;
735 const char *text = NULL;
736 const char *subText = NULL;
737 const nbgl_icon_details_t *icon = NULL;
738 uint8_t currentIndex = 0;
739 uint8_t warnIndex = 255;
740 uint8_t titleIndex = 255;
741 uint8_t subIndex = 255;
742 uint8_t approveIndex = 255;
743 uint8_t rejectIndex = 255;
744
745 context.stepCallback = NULL;
746
747 // Determine the 1st page to display tag/values
748 if (context.type == REVIEW_BLIND_SIGN_USE_CASE) {
749 // Warning page to display
750 warnIndex = currentIndex++;
751 reviewPages++;
752 }
753 // Title page to display
754 titleIndex = currentIndex++;
755 reviewPages++;
756 if (context.review.reviewSubTitle) {
757 // subtitle page to display
758 subIndex = currentIndex++;
759 reviewPages++;
760 }
761 approveIndex = context.nbPages - 2;
762 rejectIndex = context.nbPages - 1;
763 finalPages = approveIndex;
764
765 // Determine which page to display
766 if (context.currentPage >= finalPages) {
767 if (context.currentPage == approveIndex) {
768 // Approve page
769 icon = &C_icon_validate_14;
770 text = "Approve";
771 context.stepCallback = onReviewAccept;
772 }
773 else if (context.currentPage == rejectIndex) {
774 // Reject page
775 icon = &C_icon_crossmark;
776 text = "Reject";
777 context.stepCallback = onReviewReject;
778 }
779 }
780 else if (context.currentPage < reviewPages) {
781 if (context.currentPage == warnIndex) {
782 // Blind Signing Warning page
783 icon = &C_icon_warning;
784 text = "Blind\nsigning";
785 }
786 else if (context.currentPage == titleIndex) {
787 // Title page
788 icon = context.review.icon;
789 text = context.review.reviewTitle;
790 }
791 else if (context.currentPage == subIndex) {
792 // SubTitle page
793 text = context.review.reviewSubTitle;
794 }
795 }
796 else if ((context.review.address != NULL) && (context.currentPage == reviewPages)) {
797 // address confirmation and 2nd page
798 text = "Address";
799 subText = context.review.address;
800 }
801 else {
802 pairIndex = context.currentPage - reviewPages;
803 if (context.review.address != NULL) {
804 pairIndex--;
805 }
806 getPairData(context.review.tagValueList, pairIndex, &text, &subText);
807 }
808
809 drawStep(pos, icon, text, subText, reviewCallback, false);
810 nbgl_refresh();
811}
812
813// function used to display the current page in review
814static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
815{
816 const char *text = NULL;
817 const char *subText = NULL;
818 const nbgl_icon_details_t *icon = NULL;
819 uint8_t reviewPages = 0;
820 uint8_t warnIndex = 255;
821 uint8_t titleIndex = 255;
822 uint8_t subIndex = 255;
823
824 context.stepCallback = NULL;
825 context.review.dataDisplay = false;
826 switch (context.type) {
827 case STREAMING_START_REVIEW_USE_CASE:
828 case STREAMING_BLIND_SIGN_START_REVIEW_USE_CASE:
829 if (context.type == STREAMING_START_REVIEW_USE_CASE) {
830 // Title page to display
831 titleIndex = reviewPages++;
832 if (context.review.reviewSubTitle) {
833 // subtitle page to display
834 subIndex = reviewPages++;
835 }
836 }
837 else {
838 // warning page to display
839 warnIndex = reviewPages++;
840 // Title page to display
841 titleIndex = reviewPages++;
842 if (context.review.reviewSubTitle) {
843 // subtitle page to display
844 subIndex = reviewPages++;
845 }
846 }
847 // Determine which page to display
848 if (context.currentPage >= reviewPages) {
849 displaySpinner("Processing");
850 onReviewAccept();
851 return;
852 }
853 // header page(s)
854 if (context.currentPage == warnIndex) {
855 // warning page
856 icon = &C_icon_warning;
857 text = "Blind\nsigning";
858 }
859 else if (context.currentPage == titleIndex) {
860 // title page
861 icon = context.review.icon;
862 text = context.review.reviewTitle;
863 }
864 else if (context.currentPage == subIndex) {
865 // subtitle page
866 text = context.review.reviewSubTitle;
867 }
868 break;
869
870 case STREAMING_CONTINUE_REVIEW_USE_CASE:
871 if (context.currentPage >= context.review.tagValueList->nbPairs) {
872 displaySpinner("Processing");
873 onReviewAccept();
874 return;
875 }
876 context.review.dataDisplay = true;
877 getPairData(context.review.tagValueList, context.currentPage, &text, &subText);
878 break;
879
880 case STREAMING_FINISH_REVIEW_USE_CASE:
881 default:
882 if (context.currentPage == 0) {
883 // accept page
884 icon = &C_icon_validate_14;
885 text = "Approve";
886 context.stepCallback = onReviewAccept;
887 }
888 else {
889 // reject page
890 icon = &C_icon_crossmark;
891 text = "Reject";
892 context.stepCallback = onReviewReject;
893 }
894 break;
895 }
896
897 drawStep(pos, icon, text, subText, streamingReviewCallback, false);
898 nbgl_refresh();
899}
900
901// function used to display the current page in info
902static void displayInfoPage(nbgl_stepPosition_t pos)
903{
904 const char *text = NULL;
905 const char *subText = NULL;
906 const nbgl_icon_details_t *icon = NULL;
907
908 context.stepCallback = NULL;
909
910 if (context.currentPage < (context.nbPages - 1)) {
911 text = PIC(
912 ((const char *const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
913 subText = PIC(
914 ((const char *const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
915 }
916 else {
917 icon = &C_icon_back_x;
918 text = "Back";
919 context.stepCallback = startUseCaseHome;
920 }
921
922 drawStep(pos, icon, text, subText, infoCallback, false);
923 nbgl_refresh();
924}
925
926// function used to get the current page content
927static void getContentPage(bool toogle_state,
928 const char **text,
929 const char **subText,
930 const nbgl_icon_details_t **icon)
931{
932 static char fullText[75];
933 uint8_t elemIdx;
934 nbgl_state_t state = OFF_STATE;
935 const nbgl_content_t *p_content = NULL;
936 nbgl_content_t content = {0};
937 nbgl_contentSwitch_t *contentSwitch = NULL;
938#ifdef WITH_HORIZONTAL_CHOICES_LIST
939 nbgl_contentRadioChoice_t *contentChoices = NULL;
940 char **names = NULL;
941#endif
942
943 p_content = getContentElemAtIdx(context.currentPage, &elemIdx, &content);
944 if (p_content == NULL) {
945 return;
946 }
947 switch (p_content->type) {
948 case CENTERED_INFO:
949 *text = PIC(p_content->content.centeredInfo.text1);
950 *subText = PIC(p_content->content.centeredInfo.text2);
951 break;
952 case INFO_BUTTON:
953 *icon = PIC(p_content->content.infoButton.icon);
954 *text = PIC(p_content->content.infoButton.text);
955 *subText = PIC(p_content->content.infoButton.buttonText);
956 break;
957 case TAG_VALUE_LIST:
958 getPairData(&p_content->content.tagValueList, elemIdx, text, subText);
959 break;
960 case SWITCHES_LIST:
961 contentSwitch = &(
962 (nbgl_contentSwitch_t *) PIC(p_content->content.switchesList.switches))[elemIdx];
963 *text = contentSwitch->text;
964 state = contentSwitch->initState;
965 if (toogle_state) {
966 state = (state == ON_STATE) ? OFF_STATE : ON_STATE;
967 }
968 if (state == ON_STATE) {
969 snprintf(fullText, sizeof(fullText), "%s\nEnabled", contentSwitch->subText);
970 }
971 else {
972 snprintf(fullText, sizeof(fullText), "%s\nDisabled", contentSwitch->subText);
973 }
974 context.stepCallback = onSwitchAction;
975 *subText = fullText;
976 break;
977 case INFOS_LIST:
978 *text = ((const char *const *) PIC(p_content->content.infosList.infoTypes))[elemIdx];
979 *subText
980 = ((const char *const *) PIC(p_content->content.infosList.infoContents))[elemIdx];
981 break;
982 case CHOICES_LIST:
983#ifdef WITH_HORIZONTAL_CHOICES_LIST
984 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
985 *text = PIC(context.content.title);
986 *subText = PIC(p_content->content.choicesList.names[elemIdx]);
987 }
988 else {
989 contentChoices = (nbgl_contentRadioChoice_t *) PIC(&p_content->content.choicesList);
990 names = (char **) PIC(contentChoices->names);
991 *text = (const char *) PIC(names[elemIdx]);
992 }
993#endif
994 break;
995 case BARS_LIST:
996#ifdef WITH_HORIZONTAL_BARS_LIST
997 if ((context.type == CONTENT_USE_CASE) && (context.content.title != NULL)) {
998 *text = PIC(context.content.title);
999 *subText = PIC(p_content->content.barsList.barTexts[elemIdx]);
1000 }
1001 else {
1002 *text = PIC(p_content->content.barsList.barTexts[elemIdx]);
1003 }
1004#endif
1005 break;
1006 default:
1007 break;
1008 }
1009}
1010
1011// function used to display the current page in settings
1012static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state)
1013{
1014 const char *text = NULL;
1015 const char *subText = NULL;
1016 const nbgl_icon_details_t *icon = NULL;
1017
1018 context.stepCallback = NULL;
1019
1020 if (context.currentPage < (context.nbPages - 1)) {
1021 getContentPage(toogle_state, &text, &subText, &icon);
1022 }
1023 else { // last page is for quit
1024 icon = &C_icon_back_x;
1025 text = "Back";
1026 if (context.type == GENERIC_SETTINGS) {
1027 context.stepCallback = context.home.quitCallback;
1028 }
1029 else {
1030 context.stepCallback = startUseCaseHome;
1031 }
1032 }
1033
1034 drawStep(pos, icon, text, subText, settingsCallback, false);
1035 nbgl_refresh();
1036}
1037
1038static void startUseCaseHome(void)
1039{
1040 int8_t addPages = 0;
1041 if (context.home.homeAction) {
1042 // Action page index
1043 addPages++;
1044 }
1045 switch (context.type) {
1046 case SETTINGS_USE_CASE:
1047 // Settings page index
1048 context.currentPage = 1 + addPages;
1049 break;
1050 case INFO_USE_CASE:
1051 // Info page index
1052 context.currentPage = 2 + addPages;
1053 break;
1054 default:
1055 // Home page index
1056 context.currentPage = 0;
1057 break;
1058 }
1059
1060 context.type = HOME_USE_CASE;
1061 context.nbPages = 2; // Home + Quit
1062 if (context.home.settingContents) {
1063 context.nbPages++;
1064 }
1065 if (context.home.infosList) {
1066 context.nbPages++;
1067 }
1068 if (context.home.homeAction) {
1069 context.nbPages += addPages;
1070 }
1071 displayHomePage(FORWARD_DIRECTION);
1072}
1073
1074static void startUseCaseInfo(void)
1075{
1076 context.type = INFO_USE_CASE;
1077 context.nbPages = context.home.infosList->nbInfos + 1; // For back screen
1078 context.currentPage = 0;
1079
1080 displayInfoPage(FORWARD_DIRECTION);
1081}
1082
1083static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
1084{
1085 nbgl_content_t content = {0};
1086 const nbgl_content_t *p_content = NULL;
1087
1088 if (context.type == 0) {
1089 // Not yet init, it is not a GENERIC_SETTINGS
1090 context.type = SETTINGS_USE_CASE;
1091 }
1092 context.nbPages = 1; // For back screen
1093 for (int i = 0; i < context.home.settingContents->nbContents; i++) {
1094 p_content = getContentAtIdx(context.home.settingContents, i, &content);
1095 context.nbPages += getContentNbElement(p_content);
1096 }
1097 context.currentPage = initSettingPage;
1098
1099 displaySettingsPage(FORWARD_DIRECTION, false);
1100}
1101
1102static void startUseCaseSettings(void)
1103{
1104 startUseCaseSettingsAtPage(0);
1105}
1106
1107static void startUseCaseContent(void)
1108{
1109 uint8_t contentIdx = 0;
1110 const nbgl_content_t *p_content = NULL;
1111 nbgl_content_t content = {0};
1112
1113 context.nbPages = 1; // Quit
1114
1115 for (contentIdx = 0; contentIdx < context.content.genericContents.nbContents; contentIdx++) {
1116 p_content = getContentAtIdx(&context.content.genericContents, contentIdx, &content);
1117 context.nbPages += getContentNbElement(p_content);
1118 }
1119
1120 displayContent(FORWARD_DIRECTION, false);
1121}
1122
1123// function used to display the current page in home
1124static void displayHomePage(nbgl_stepPosition_t pos)
1125{
1126 const char *text = NULL;
1127 const char *subText = NULL;
1128 const nbgl_icon_details_t *icon = NULL;
1129 uint8_t currentIndex = 0;
1130 uint8_t homeIndex = 255;
1131 uint8_t actionIndex = 255;
1132 uint8_t settingsIndex = 255;
1133 uint8_t infoIndex = 255;
1134
1135 context.stepCallback = NULL;
1136
1137 // Determine which pages are present
1138 homeIndex = currentIndex++;
1139 if (context.home.homeAction) {
1140 actionIndex = currentIndex++;
1141 }
1142 if (context.home.settingContents) {
1143 settingsIndex = currentIndex++;
1144 }
1145 if (context.home.infosList) {
1146 infoIndex = currentIndex++;
1147 }
1148
1149 if (context.currentPage == homeIndex) {
1150 // Home page
1151 icon = context.home.appIcon;
1152 if (context.home.tagline != NULL) {
1153 text = context.home.tagline;
1154 }
1155 else {
1156 text = context.home.appName;
1157 subText = "is ready";
1158 }
1159 }
1160 else if (context.currentPage == actionIndex) {
1161 // Action page
1162 icon = context.home.homeAction->icon;
1163 text = PIC(context.home.homeAction->text);
1164 context.stepCallback = context.home.homeAction->callback;
1165 }
1166 else if (context.currentPage == settingsIndex) {
1167 // Settings page
1168 icon = &C_icon_coggle;
1169 text = "Settings";
1170 context.stepCallback = startUseCaseSettings;
1171 }
1172 else if (context.currentPage == infoIndex) {
1173 // About page
1174 icon = &C_icon_certificate;
1175 text = "About";
1176 context.stepCallback = startUseCaseInfo;
1177 }
1178 else {
1179 icon = &C_icon_dashboard_x;
1180 text = "Quit";
1181 context.stepCallback = context.home.quitCallback;
1182 }
1183
1184 drawStep(pos, icon, text, subText, homeCallback, false);
1185 nbgl_refresh();
1186}
1187
1188// function used to display the current page in choice
1189static void displayChoicePage(nbgl_stepPosition_t pos)
1190{
1191 const char *text = NULL;
1192 const char *subText = NULL;
1193 const nbgl_icon_details_t *icon = NULL;
1194
1195 context.stepCallback = NULL;
1196
1197 // Handle case where there is no icon or subMessage
1198 if (context.currentPage == 1
1199 && (context.choice.icon == NULL || context.choice.subMessage == NULL)) {
1200 if (pos & BACKWARD_DIRECTION) {
1201 context.currentPage -= 1;
1202 }
1203 else {
1204 context.currentPage += 1;
1205 }
1206 }
1207
1208 if (context.currentPage == 0) { // title page
1209 text = context.choice.message;
1210 if (context.choice.icon != NULL) {
1211 icon = context.choice.icon;
1212 }
1213 else {
1214 subText = context.choice.subMessage;
1215 }
1216 }
1217 else if (context.currentPage == 1) { // sub-title page
1218 // displayed only if there is both icon and submessage
1219 text = context.choice.message;
1220 subText = context.choice.subMessage;
1221 }
1222 else if (context.currentPage == 2) { // confirm page
1223 icon = &C_icon_validate_14;
1224 text = context.choice.confirmText;
1225 context.stepCallback = onChoiceAccept;
1226 }
1227 else { // cancel page
1228 icon = &C_icon_crossmark;
1229 text = context.choice.cancelText;
1230 context.stepCallback = onChoiceReject;
1231 }
1232
1233 drawStep(pos, icon, text, subText, genericChoiceCallback, false);
1234 nbgl_refresh();
1235}
1236
1237// function used to display the Confirm page
1238static void displayConfirm(nbgl_stepPosition_t pos)
1239{
1240 const char *text = NULL;
1241 const char *subText = NULL;
1242 const nbgl_icon_details_t *icon = NULL;
1243
1244 context.stepCallback = NULL;
1245 switch (context.currentPage) {
1246 case 0:
1247 // title page
1248 text = context.confirm.message;
1249 subText = context.confirm.subMessage;
1250 break;
1251 case 1:
1252 // confirm page
1253 icon = &C_icon_validate_14;
1254 text = context.confirm.confirmText;
1255 context.stepCallback = onConfirmAccept;
1256 break;
1257 case 2:
1258 // cancel page
1259 icon = &C_icon_crossmark;
1260 text = context.confirm.cancelText;
1261 context.stepCallback = onConfirmReject;
1262 break;
1263 }
1264
1265 drawStep(pos, icon, text, subText, genericConfirmCallback, true);
1266 nbgl_refresh();
1267}
1268
1269// function used to display the current navigable content
1270static void displayContent(nbgl_stepPosition_t pos, bool toogle_state)
1271{
1272 const char *text = NULL;
1273 const char *subText = NULL;
1274 const nbgl_icon_details_t *icon = NULL;
1275
1276 context.stepCallback = NULL;
1277
1278 if (context.currentPage < (context.nbPages - 1)) {
1279 getContentPage(toogle_state, &text, &subText, &icon);
1280 }
1281 else { // last page is for quit
1282 if (context.content.rejectText) {
1283 text = context.content.rejectText;
1284 }
1285 else {
1286 text = "Back";
1287 }
1288 if (context.type == GENERIC_REVIEW_USE_CASE) {
1289 icon = &C_icon_crossmark;
1290 }
1291 else {
1292 icon = &C_icon_back_x;
1293 }
1294 context.stepCallback = context.content.quitCallback;
1295 }
1296
1297 drawStep(pos, icon, text, subText, contentCallback, false);
1298 nbgl_refresh();
1299}
1300
1301static void displaySpinner(const char *text)
1302{
1303 drawStep(SINGLE_STEP, &C_icon_processing, text, NULL, NULL, false);
1304 nbgl_refresh();
1305}
1306
1307// function to factorize code for all simple reviews
1308static void useCaseReview(ContextType_t type,
1309 const nbgl_contentTagValueList_t *tagValueList,
1310 const nbgl_icon_details_t *icon,
1311 const char *reviewTitle,
1312 const char *reviewSubTitle,
1313 const char *finishTitle,
1314 nbgl_choiceCallback_t choiceCallback)
1315{
1316 UNUSED(finishTitle); // TODO dedicated screen for it?
1317
1318 memset(&context, 0, sizeof(UseCaseContext_t));
1319 context.type = type;
1320 context.review.tagValueList = tagValueList;
1321 context.review.reviewTitle = reviewTitle;
1322 context.review.reviewSubTitle = reviewSubTitle;
1323 context.review.icon = icon;
1324 context.review.onChoice = choiceCallback;
1325 context.currentPage = 0;
1326 // 1 page for title and 2 pages at the end for accept/reject
1327 context.nbPages = tagValueList->nbPairs + 3;
1328 if (type == REVIEW_BLIND_SIGN_USE_CASE) {
1329 context.nbPages++; // 1 page for warning
1330 }
1331 if (reviewSubTitle) {
1332 context.nbPages++; // 1 page for subtitle page
1333 }
1334
1335 displayReviewPage(FORWARD_DIRECTION);
1336}
1337
1338#ifdef NBGL_KEYPAD
1339static void setPinCodeText(void)
1340{
1341 bool enableValidate = false;
1342 bool enableBackspace = true;
1343
1344 // pin can be validated when min digits is entered
1345 enableValidate = (context.keypad.pinLen >= context.keypad.pinMinDigits);
1346 // backspace is disabled when no digit is entered and back vallback is not provided
1347 enableBackspace = (context.keypad.pinLen > 0) || (context.keypad.backCallback != NULL);
1348 nbgl_layoutUpdateKeypadContent(context.keypad.layoutCtx,
1349 context.keypad.hidden,
1350 context.keypad.pinLen,
1351 (const char *) context.keypad.pinEntry);
1353 context.keypad.layoutCtx, context.keypad.keypadIndex, enableValidate, enableBackspace);
1354 nbgl_layoutDraw(context.keypad.layoutCtx);
1355 nbgl_refresh();
1356}
1357
1358// called when a key is touched on the keypad
1359static void keypadCallback(char touchedKey)
1360{
1361 switch (touchedKey) {
1362 case BACKSPACE_KEY:
1363 if (context.keypad.pinLen > 0) {
1364 context.keypad.pinLen--;
1365 context.keypad.pinEntry[context.keypad.pinLen] = 0;
1366 }
1367 else if (context.keypad.backCallback != NULL) {
1368 context.keypad.backCallback();
1369 break;
1370 }
1371 setPinCodeText();
1372 break;
1373
1374 case VALIDATE_KEY:
1375 context.keypad.validatePin(context.keypad.pinEntry, context.keypad.pinLen);
1376 break;
1377
1378 default:
1379 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1380 if (context.keypad.pinLen < context.keypad.pinMaxDigits) {
1381 context.keypad.pinEntry[context.keypad.pinLen] = touchedKey;
1382 context.keypad.pinLen++;
1383 }
1384 setPinCodeText();
1385 }
1386 break;
1387 }
1388}
1389
1390// called to create a keypad, with either hidden or visible digits
1391static void keypadGenericUseCase(const char *title,
1392 uint8_t minDigits,
1393 uint8_t maxDigits,
1394 bool shuffled,
1395 bool hidden,
1396 nbgl_pinValidCallback_t validatePinCallback,
1397 nbgl_callback_t backCallback)
1398{
1399 nbgl_layoutDescription_t layoutDescription = {0};
1400 int status = -1;
1401
1402 // reset the keypad context
1403 memset(&context, 0, sizeof(KeypadContext_t));
1404 context.type = KEYPAD_USE_CASE;
1405 context.currentPage = 0;
1406 context.nbPages = 1;
1407 context.keypad.validatePin = validatePinCallback;
1408 context.keypad.backCallback = backCallback;
1409 context.keypad.pinMinDigits = minDigits;
1410 context.keypad.pinMaxDigits = maxDigits;
1411 context.keypad.hidden = hidden;
1412 context.keypad.layoutCtx = nbgl_layoutGet(&layoutDescription);
1413
1414 // add keypad
1415 status = nbgl_layoutAddKeypad(context.keypad.layoutCtx, keypadCallback, title, shuffled);
1416 if (status < 0) {
1417 return;
1418 }
1419 context.keypad.keypadIndex = status;
1420 // add digits
1421 status = nbgl_layoutAddKeypadContent(context.keypad.layoutCtx, hidden, maxDigits, "");
1422 if (status < 0) {
1423 return;
1424 }
1425
1426 nbgl_layoutDraw(context.keypad.layoutCtx);
1427 if (context.keypad.backCallback != NULL) {
1428 // force backspace to be visible at first digit, to be used as quit
1429 nbgl_layoutUpdateKeypad(context.keypad.layoutCtx, context.keypad.keypadIndex, false, true);
1430 }
1431 nbgl_refresh();
1432}
1433#endif // NBGL_KEYPAD
1434
1435/**********************
1436 * GLOBAL FUNCTIONS
1437 **********************/
1438
1451 const nbgl_contentTagValueList_t *tagValueList,
1452 uint8_t startIndex,
1453 bool *requireSpecificDisplay)
1454{
1455 UNUSED(nbPairs);
1456 UNUSED(tagValueList);
1457 UNUSED(startIndex);
1458 *requireSpecificDisplay = true;
1459 return 1;
1460}
1461
1475 const nbgl_contentTagValueList_t *tagValueList,
1476 uint8_t startIndex,
1477 bool isSkippable,
1478 bool *requireSpecificDisplay)
1479{
1480 UNUSED(nbPairs);
1481 UNUSED(tagValueList);
1482 UNUSED(startIndex);
1483 UNUSED(isSkippable);
1484 *requireSpecificDisplay = true;
1485 return 1;
1486}
1487
1497 const nbgl_contentInfoList_t *infosList,
1498 uint8_t startIndex,
1499 bool withNav)
1500{
1501 UNUSED(nbInfos);
1502 UNUSED(infosList);
1503 UNUSED(startIndex);
1504 UNUSED(withNav);
1505 return 1;
1506}
1507
1517 const nbgl_contentSwitchesList_t *switchesList,
1518 uint8_t startIndex,
1519 bool withNav)
1520{
1521 UNUSED(nbSwitches);
1522 UNUSED(switchesList);
1523 UNUSED(startIndex);
1524 UNUSED(withNav);
1525 return 1;
1526}
1527
1537 const nbgl_contentBarsList_t *barsList,
1538 uint8_t startIndex,
1539 bool withNav)
1540{
1541 UNUSED(nbBars);
1542 UNUSED(barsList);
1543 UNUSED(startIndex);
1544 UNUSED(withNav);
1545 return 1;
1546}
1547
1557 const nbgl_contentRadioChoice_t *choicesList,
1558 uint8_t startIndex,
1559 bool withNav)
1560{
1561 UNUSED(nbChoices);
1562 UNUSED(choicesList);
1563 UNUSED(startIndex);
1564 UNUSED(withNav);
1565 return 1;
1566}
1567
1575{
1576 uint8_t nbPages = 0;
1577 uint8_t nbPairs = tagValueList->nbPairs;
1578 uint8_t nbPairsInPage;
1579 uint8_t i = 0;
1580 bool flag;
1581
1582 while (i < tagValueList->nbPairs) {
1583 // upper margin
1584 nbPairsInPage = nbgl_useCaseGetNbTagValuesInPageExt(nbPairs, tagValueList, i, false, &flag);
1585 i += nbPairsInPage;
1586 nbPairs -= nbPairsInPage;
1587 nbPages++;
1588 }
1589 return nbPages;
1590}
1591
1605void nbgl_useCaseNavigableContent(const char *title,
1606 uint8_t initPage,
1607 uint8_t nbPages,
1608 nbgl_callback_t quitCallback,
1609 nbgl_navCallback_t navCallback,
1610 nbgl_layoutTouchCallback_t controlsCallback)
1611{
1612 nbgl_pageContent_t pageContent = {0};
1613 static nbgl_content_t contentsList = {0};
1614
1615 if (initPage >= nbPages) {
1616 return;
1617 }
1618 // Use Callback to get the page content
1619 if (navCallback(initPage, &pageContent) == false) {
1620 return;
1621 }
1622 memset(&context, 0, sizeof(UseCaseContext_t));
1623 context.type = CONTENT_USE_CASE;
1624 context.content.quitCallback = quitCallback;
1625 context.content.controlsCallback = controlsCallback;
1626 context.content.genericContents.callbackCallNeeded = false;
1627 context.content.genericContents.nbContents = nbPages;
1628
1629 contentsList.type = pageContent.type;
1630 switch (pageContent.type) {
1631 case CENTERED_INFO:
1632 contentsList.content.centeredInfo = pageContent.centeredInfo;
1633 break;
1634 case INFO_BUTTON:
1635 contentsList.content.infoButton = pageContent.infoButton;
1636 break;
1637 case TAG_VALUE_LIST:
1638 contentsList.content.tagValueList = pageContent.tagValueList;
1639 break;
1640 case SWITCHES_LIST:
1641 contentsList.content.switchesList = pageContent.switchesList;
1642 break;
1643 case INFOS_LIST:
1644 contentsList.content.infosList = pageContent.infosList;
1645 break;
1646 case CHOICES_LIST:
1647 contentsList.content.choicesList = pageContent.choicesList;
1648 context.content.title = title;
1649 context.currentPage = pageContent.choicesList.initChoice;
1650 break;
1651 case BARS_LIST:
1652 contentsList.content.barsList = pageContent.barsList;
1653 context.content.title = title;
1654 break;
1655 default:
1656 break;
1657 }
1658 context.content.genericContents.contentsList = (const nbgl_content_t *) &contentsList;
1659
1660 startUseCaseContent();
1661}
1662
1677void nbgl_useCaseHomeAndSettings(const char *appName,
1678 const nbgl_icon_details_t *appIcon,
1679 const char *tagline,
1680 const uint8_t initSettingPage,
1681 const nbgl_genericContents_t *settingContents,
1682 const nbgl_contentInfoList_t *infosList,
1683 const nbgl_homeAction_t *action,
1684 nbgl_callback_t quitCallback)
1685{
1686 memset(&context, 0, sizeof(UseCaseContext_t));
1687 context.home.appName = appName;
1688 context.home.appIcon = appIcon;
1689 context.home.tagline = tagline;
1690 context.home.settingContents = PIC(settingContents);
1691 context.home.infosList = PIC(infosList);
1692 context.home.homeAction = action;
1693 context.home.quitCallback = quitCallback;
1694
1695 if (initSettingPage != INIT_HOME_PAGE) {
1696 startUseCaseSettingsAtPage(initSettingPage);
1697 }
1698 else {
1699 startUseCaseHome();
1700 }
1701}
1702
1715void nbgl_useCaseGenericSettings(const char *appName,
1716 uint8_t initPage,
1717 const nbgl_genericContents_t *settingContents,
1718 const nbgl_contentInfoList_t *infosList,
1719 nbgl_callback_t quitCallback)
1720{
1721 memset(&context, 0, sizeof(UseCaseContext_t));
1722 context.type = GENERIC_SETTINGS;
1723 context.home.appName = appName;
1724 context.home.settingContents = PIC(settingContents);
1725 context.home.infosList = PIC(infosList);
1726 context.home.quitCallback = quitCallback;
1727
1728 startUseCaseSettingsAtPage(initPage);
1729}
1730
1742void nbgl_useCaseGenericConfiguration(const char *title,
1743 uint8_t initPage,
1744 const nbgl_genericContents_t *contents,
1745 nbgl_callback_t quitCallback)
1746{
1747 nbgl_useCaseGenericSettings(title, initPage, contents, NULL, quitCallback);
1748}
1749
1764void nbgl_useCaseReview(nbgl_operationType_t operationType,
1765 const nbgl_contentTagValueList_t *tagValueList,
1766 const nbgl_icon_details_t *icon,
1767 const char *reviewTitle,
1768 const char *reviewSubTitle,
1769 const char *finishTitle,
1770 nbgl_choiceCallback_t choiceCallback)
1771{
1772 UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
1773
1774 useCaseReview(REVIEW_USE_CASE,
1775 tagValueList,
1776 icon,
1777 reviewTitle,
1778 reviewSubTitle,
1779 finishTitle,
1780 choiceCallback);
1781}
1782
1801 const nbgl_contentTagValueList_t *tagValueList,
1802 const nbgl_icon_details_t *icon,
1803 const char *reviewTitle,
1804 const char *reviewSubTitle,
1805 const char *finishTitle,
1806 const nbgl_tipBox_t *dummy,
1807 nbgl_choiceCallback_t choiceCallback)
1808{
1809 UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
1810 UNUSED(dummy);
1811
1812 useCaseReview(REVIEW_USE_CASE,
1813 tagValueList,
1814 icon,
1815 reviewTitle,
1816 reviewSubTitle,
1817 finishTitle,
1818 choiceCallback);
1819}
1820
1841 const nbgl_contentTagValueList_t *tagValueList,
1842 const nbgl_icon_details_t *icon,
1843 const char *reviewTitle,
1844 const char *reviewSubTitle,
1845 const char *finishTitle,
1846 const nbgl_tipBox_t *dummy,
1847 nbgl_choiceCallback_t choiceCallback)
1848{
1849 UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
1850 UNUSED(dummy);
1851
1852 useCaseReview(REVIEW_BLIND_SIGN_USE_CASE,
1853 tagValueList,
1854 icon,
1855 reviewTitle,
1856 reviewSubTitle,
1857 finishTitle,
1858 choiceCallback);
1859}
1860
1876 const nbgl_contentTagValueList_t *tagValueList,
1877 const nbgl_icon_details_t *icon,
1878 const char *reviewTitle,
1879 const char *reviewSubTitle,
1880 const char *finishTitle,
1881 nbgl_choiceCallback_t choiceCallback)
1882{
1883 return nbgl_useCaseReview(operationType,
1884 tagValueList,
1885 icon,
1886 reviewTitle,
1887 reviewSubTitle,
1888 finishTitle,
1889 choiceCallback);
1890}
1891
1908void nbgl_useCaseAddressReview(const char *address,
1909 const nbgl_contentTagValueList_t *additionalTagValueList,
1910 const nbgl_icon_details_t *icon,
1911 const char *reviewTitle,
1912 const char *reviewSubTitle,
1913 nbgl_choiceCallback_t choiceCallback)
1914{
1915 memset(&context, 0, sizeof(UseCaseContext_t));
1916 context.type = ADDRESS_REVIEW_USE_CASE;
1917 context.review.address = address;
1918 context.review.reviewTitle = reviewTitle;
1919 context.review.reviewSubTitle = reviewSubTitle;
1920 context.review.icon = icon;
1921 context.review.onChoice = choiceCallback;
1922 context.currentPage = 0;
1923 // + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
1924 context.nbPages = 4;
1925 if (additionalTagValueList) {
1926 context.review.tagValueList = PIC(additionalTagValueList);
1927 context.nbPages += additionalTagValueList->nbPairs;
1928 }
1929
1930 displayReviewPage(FORWARD_DIRECTION);
1931}
1932
1942 const char *rejectText,
1943 nbgl_callback_t rejectCallback)
1944{
1945 memset(&context, 0, sizeof(UseCaseContext_t));
1946 context.type = GENERIC_REVIEW_USE_CASE;
1947 context.content.rejectText = rejectText;
1948 context.content.quitCallback = rejectCallback;
1949 context.content.genericContents.nbContents = contents->nbContents;
1950 context.content.genericContents.callbackCallNeeded = contents->callbackCallNeeded;
1951 if (contents->callbackCallNeeded) {
1952 context.content.genericContents.contentGetterCallback = contents->contentGetterCallback;
1953 }
1954 else {
1955 context.content.genericContents.contentsList = PIC(contents->contentsList);
1956 }
1957
1958 startUseCaseContent();
1959}
1960
1968void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
1969{
1970 const nbgl_icon_details_t *icon = NULL;
1971
1972 memset(&context, 0, sizeof(UseCaseContext_t));
1973 context.type = STATUS_USE_CASE;
1974 context.stepCallback = quitCallback;
1975 context.currentPage = 0;
1976 context.nbPages = 1;
1977
1978 icon = isSuccess ? &C_icon_validate_14 : &C_icon_crossmark;
1979 drawStep(SINGLE_STEP, icon, message, NULL, statusButtonCallback, false);
1980}
1981
1989 nbgl_callback_t quitCallback)
1990{
1991 const char *msg;
1992 bool isSuccess;
1993 switch (reviewStatusType) {
1995 msg = "Operation signed";
1996 isSuccess = true;
1997 break;
1999 msg = "Operation rejected";
2000 isSuccess = false;
2001 break;
2003 msg = "Transaction signed";
2004 isSuccess = true;
2005 break;
2007 msg = "Transaction rejected";
2008 isSuccess = false;
2009 break;
2011 msg = "Message signed";
2012 isSuccess = true;
2013 break;
2015 msg = "Message rejected";
2016 isSuccess = false;
2017 break;
2019 msg = "Address verified";
2020 isSuccess = true;
2021 break;
2023 msg = "Address verification cancelled";
2024 isSuccess = false;
2025 break;
2026 default:
2027 return;
2028 }
2029 nbgl_useCaseStatus(msg, isSuccess, quitCallback);
2030}
2031
2045 const nbgl_icon_details_t *icon,
2046 const char *reviewTitle,
2047 const char *reviewSubTitle,
2048 nbgl_choiceCallback_t choiceCallback)
2049{
2050 UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
2051
2052 memset(&context, 0, sizeof(UseCaseContext_t));
2053 context.type = STREAMING_START_REVIEW_USE_CASE;
2054 context.review.reviewTitle = reviewTitle;
2055 context.review.reviewSubTitle = reviewSubTitle;
2056 context.review.icon = icon;
2057 context.review.onChoice = choiceCallback;
2058 context.currentPage = 0;
2059 context.nbPages = 2; // Start page + trick for review continue
2060
2061 displayStreamingReviewPage(FORWARD_DIRECTION);
2062}
2063
2078 const nbgl_icon_details_t *icon,
2079 const char *reviewTitle,
2080 const char *reviewSubTitle,
2081 nbgl_choiceCallback_t choiceCallback)
2082{
2083 UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
2084
2085 memset(&context, 0, sizeof(UseCaseContext_t));
2086 context.type = STREAMING_BLIND_SIGN_START_REVIEW_USE_CASE;
2087 context.review.reviewTitle = reviewTitle;
2088 context.review.reviewSubTitle = reviewSubTitle;
2089 context.review.icon = icon;
2090 context.review.onChoice = choiceCallback;
2091 context.currentPage = 0;
2092 context.nbPages = 3; // Warning + Start page + trick for review continue
2093
2094 displayStreamingReviewPage(FORWARD_DIRECTION);
2095}
2096
2111 nbgl_choiceCallback_t choiceCallback,
2112 nbgl_callback_t skipCallback)
2113{
2114 memset(&context, 0, sizeof(UseCaseContext_t));
2115 context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
2116 context.review.tagValueList = tagValueList;
2117 context.review.onChoice = choiceCallback;
2118 context.currentPage = 0;
2119 context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
2120 context.review.skipCallback = skipCallback;
2121
2122 displayStreamingReviewPage(FORWARD_DIRECTION);
2123}
2124
2136 nbgl_choiceCallback_t choiceCallback)
2137{
2138 nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL);
2139}
2140
2141void nbgl_useCaseReviewStreamingFinish(const char *finishTitle,
2142 nbgl_choiceCallback_t choiceCallback)
2143{
2144 UNUSED(finishTitle); // TODO dedicated screen for it?
2145
2146 memset(&context, 0, sizeof(UseCaseContext_t));
2147 context.type = STREAMING_FINISH_REVIEW_USE_CASE;
2148 context.review.onChoice = choiceCallback;
2149 context.currentPage = 0;
2150 context.nbPages = 2; // 2 pages at the end for accept/reject
2151
2152 displayStreamingReviewPage(FORWARD_DIRECTION);
2153}
2154
2160void nbgl_useCaseSpinner(const char *text)
2161{
2162 memset(&context, 0, sizeof(UseCaseContext_t));
2163 context.type = SPINNER_USE_CASE;
2164 context.currentPage = 0;
2165 context.nbPages = 1;
2166
2167 displaySpinner(text);
2168}
2169
2171 const char *message,
2172 const char *subMessage,
2173 const char *confirmText,
2174 const char *cancelText,
2175 nbgl_choiceCallback_t callback)
2176{
2177 memset(&context, 0, sizeof(UseCaseContext_t));
2178 context.type = CHOICE_USE_CASE;
2179 context.choice.icon = icon;
2180 context.choice.message = message;
2181 context.choice.subMessage = subMessage;
2182 context.choice.confirmText = confirmText;
2183 context.choice.cancelText = cancelText;
2184 context.choice.onChoice = callback;
2185 context.currentPage = 0;
2186 context.nbPages = 1 + 1 + 2; // 2 pages at the end for confirm/cancel
2187
2188 displayChoicePage(FORWARD_DIRECTION);
2189};
2190
2204void nbgl_useCaseConfirm(const char *message,
2205 const char *subMessage,
2206 const char *confirmText,
2207 const char *cancelText,
2208 nbgl_callback_t callback)
2209{
2210 memset(&context, 0, sizeof(UseCaseContext_t));
2211 context.type = CONFIRM_USE_CASE;
2212 context.confirm.message = message;
2213 context.confirm.subMessage = subMessage;
2214 context.confirm.confirmText = confirmText;
2215 context.confirm.cancelText = cancelText;
2216 context.confirm.onConfirm = callback;
2217 context.currentPage = 0;
2218 context.nbPages = 1 + 2; // 2 pages at the end for confirm/cancel
2219
2220 displayConfirm(FORWARD_DIRECTION);
2221}
2222
2223#ifdef NBGL_KEYPAD
2241void nbgl_useCaseKeypadDigits(const char *title,
2242 uint8_t minDigits,
2243 uint8_t maxDigits,
2244 bool shuffled,
2245 nbgl_pinValidCallback_t validatePinCallback,
2246 nbgl_callback_t backCallback)
2247{
2248 keypadGenericUseCase(
2249 title, minDigits, maxDigits, shuffled, false, validatePinCallback, backCallback);
2250}
2251
2270void nbgl_useCaseKeypadPIN(const char *title,
2271 uint8_t minDigits,
2272 uint8_t maxDigits,
2273 bool shuffled,
2274 nbgl_pinValidCallback_t validatePinCallback,
2275 nbgl_callback_t backCallback)
2276{
2277 keypadGenericUseCase(
2278 title, minDigits, maxDigits, shuffled, true, validatePinCallback, backCallback);
2279}
2280#endif // NBGL_KEYPAD
2281
2282#endif // HAVE_SE_TOUCH
2283#endif // NBGL_USE_CASE
@ 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
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_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:1559
nbgl_buttonEvent_t
Definition nbgl_obj.h:203
@ BUTTON_BOTH_PRESSED
Sent when both buttons are released.
Definition nbgl_obj.h:210
@ BUTTON_LEFT_PRESSED
Sent when Left button is released.
Definition nbgl_obj.h:204
@ BUTTON_RIGHT_PRESSED
Send when Right button is released.
Definition nbgl_obj.h:205
#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
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
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:179
@ ON_STATE
Definition nbgl_types.h:181
@ OFF_STATE
Definition nbgl_types.h:180
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)
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)
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_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, 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)
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.
uint8_t nbInfos
number of elements in infoTypes and infoContents array
const char *const * infoContents
array of contents of infos (in black)
const char *const * infoTypes
array of types of infos (in black/bold)
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
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.
const char * value
string giving the value name
const char * item
string giving the tag name
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...
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