Embedded SDK
Embedded SDK
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 
24 /**********************
25  * TYPEDEFS
26  **********************/
27 
28 typedef struct ReviewContext_s {
29  nbgl_choiceCallback_t onChoice;
30  const nbgl_contentTagValueList_t *tagValueList;
31  const nbgl_icon_details_t *icon;
32  const char *reviewTitle;
33  const char *address; // for address confirmation review
34 } ReviewContext_t;
35 
36 typedef struct ChoiceContext_s {
37  const nbgl_icon_details_t *icon;
38  const char *message;
39  const char *subMessage;
40  const char *confirmText;
41  const char *cancelText;
42  nbgl_choiceCallback_t onChoice;
43 } ChoiceContext_t;
44 
45 typedef struct HomeContext_s {
46  const char *appName;
47  const nbgl_icon_details_t *appIcon;
48  const char *tagline;
49  const nbgl_genericContents_t *settingContents;
50  const nbgl_contentInfoList_t *infosList;
51  nbgl_callback_t quitCallback;
52 } HomeContext_t;
53 
54 typedef enum {
55  NONE_USE_CASE,
56  REVIEW_USE_CASE,
57  ADDRESS_REVIEW_USE_CASE,
58  STREAMING_START_REVIEW_USE_CASE,
59  STREAMING_CONTINUE_REVIEW_USE_CASE,
60  STREAMING_FINISH_REVIEW_USE_CASE,
61  CHOICE_USE_CASE,
62  HOME_USE_CASE,
63  INFO_USE_CASE,
64  SETTINGS_USE_CASE,
65 } ContextType_t;
66 
67 typedef struct UseCaseContext_s {
68  ContextType_t type;
69  uint8_t nbPages;
70  int8_t currentPage;
72  stepCallback;
73  union {
74  ReviewContext_t review;
75  ChoiceContext_t choice;
76  HomeContext_t home;
77  };
78 } UseCaseContext_t;
79 
80 /**********************
81  * STATIC VARIABLES
82  **********************/
83 static UseCaseContext_t context;
84 
85 /**********************
86  * STATIC FUNCTIONS
87  **********************/
88 static void displayReviewPage(nbgl_stepPosition_t pos);
89 static void displayStreamingReviewPage(nbgl_stepPosition_t pos);
90 static void displayHomePage(nbgl_stepPosition_t pos);
91 static void displayInfoPage(nbgl_stepPosition_t pos);
92 static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state);
93 static void displayChoicePage(nbgl_stepPosition_t pos);
94 
95 static void startUseCaseHome(void);
96 static void startUseCaseInfo(void);
97 static void startUseCaseSettings(void);
98 static void startUseCaseSettingsAtPage(uint8_t initSettingPage);
99 
100 // Simple helper to get the number of elements inside a nbgl_content_t
101 static uint8_t getContentNbElement(const nbgl_content_t *content)
102 {
103  switch (content->type) {
104  case TAG_VALUE_LIST:
105  return content->content.tagValueList.nbPairs;
106  case SWITCHES_LIST:
107  return content->content.switchesList.nbSwitches;
108  case INFOS_LIST:
109  return content->content.infosList.nbInfos;
110  default:
111  return 0;
112  }
113 }
114 
115 // Helper to retrieve the content inside a nbgl_genericContents_t using
116 // either the contentsList or using the contentGetterCallback
117 static const nbgl_content_t *getContentAtIdx(const nbgl_genericContents_t *genericContents,
118  int8_t contentIdx,
119  nbgl_content_t *content)
120 {
121  if (contentIdx < 0 || contentIdx >= genericContents->nbContents) {
122  LOG_DEBUG(USE_CASE_LOGGER, "No content available at %d\n", contentIdx);
123  return NULL;
124  }
125 
126  if (genericContents->callbackCallNeeded) {
127  // Retrieve content through callback, but first memset the content.
128  memset(content, 0, sizeof(nbgl_content_t));
129  genericContents->contentGetterCallback(contentIdx, content);
130  return content;
131  }
132  else {
133  // Retrieve content through list
134  return PIC(&genericContents->contentsList[contentIdx]);
135  }
136 }
137 
138 // Helper to retrieve the content inside a nbgl_genericContents_t using
139 // either the contentsList or using the contentGetterCallback
140 static const nbgl_content_t *getContentElemAtIdx(const nbgl_genericContents_t *genericContents,
141  uint8_t elemIdx,
142  uint8_t *elemContentIdx,
143  nbgl_content_t *content)
144 {
145  const nbgl_content_t *p_content;
146  uint8_t nbPages = 0;
147  uint8_t elemNbPages = 0;
148 
149  for (int i = 0; i < genericContents->nbContents; i++) {
150  p_content = getContentAtIdx(genericContents, i, content);
151  elemNbPages = getContentNbElement(p_content);
152  if (nbPages + elemNbPages > elemIdx) {
153  *elemContentIdx = context.currentPage - nbPages;
154  break;
155  }
156  nbPages += elemNbPages;
157  }
158 
159  return p_content;
160 }
161 
162 static void getPairData(const nbgl_contentTagValueList_t *tagValueList,
163  uint8_t index,
164  const char **item,
165  const char **value)
166 {
167  const nbgl_contentTagValue_t *pair;
168 
169  if (tagValueList->pairs != NULL) {
170  pair = PIC(&tagValueList->pairs[index]);
171  }
172  else {
173  pair = PIC(tagValueList->callback(index));
174  }
175  *item = pair->item;
176  *value = pair->value;
177 }
178 
179 static void onReviewAccept(void)
180 {
181  if (context.review.onChoice) {
182  context.review.onChoice(true);
183  }
184 }
185 
186 static void onReviewReject(void)
187 {
188  if (context.review.onChoice) {
189  context.review.onChoice(false);
190  }
191 }
192 
193 static void onChoiceAccept(void)
194 {
195  if (context.choice.onChoice) {
196  context.choice.onChoice(true);
197  }
198 }
199 
200 static void onChoiceReject(void)
201 {
202  if (context.choice.onChoice) {
203  context.choice.onChoice(false);
204  }
205 }
206 
207 static void onSettingsAction(void)
208 {
209  nbgl_content_t content;
210  uint8_t elemIdx;
211 
212  const nbgl_content_t *p_content = getContentElemAtIdx(
213  context.home.settingContents, context.currentPage, &elemIdx, &content);
214 
215  switch (p_content->type) {
216  case SWITCHES_LIST: {
217  const nbgl_contentSwitch_t *contentSwitch = &((const nbgl_contentSwitch_t *) PIC(
218  p_content->content.switchesList.switches))[elemIdx];
219  nbgl_state_t state = (contentSwitch->initState == ON_STATE) ? OFF_STATE : ON_STATE;
220  displaySettingsPage(FORWARD_DIRECTION, true);
221  if (p_content->contentActionCallback != NULL) {
222  nbgl_contentActionCallback_t onContentAction
223  = PIC(p_content->contentActionCallback);
224  onContentAction(contentSwitch->token, state, context.currentPage);
225  }
226  break;
227  }
228  default:
229  break;
230  }
231 }
232 
233 static void drawStep(nbgl_stepPosition_t pos,
234  const nbgl_icon_details_t *icon,
235  const char *txt,
236  const char *subTxt,
237  nbgl_stepButtonCallback_t onActionCallback)
238 {
239  pos |= GET_POS_OF_STEP(context.currentPage, context.nbPages);
240 
241  if (icon == NULL) {
242  nbgl_stepDrawText(pos, onActionCallback, NULL, txt, subTxt, BOLD_TEXT1_INFO, false);
243  }
244  else {
246  info.icon = icon;
247  info.text1 = txt;
248  info.text2 = subTxt;
249  info.onTop = false;
250  info.style = BOLD_TEXT1_INFO;
251  nbgl_stepDrawCenteredInfo(pos, onActionCallback, NULL, &info, false);
252  }
253 }
254 
255 static bool buttonGenericCallback(nbgl_buttonEvent_t event, nbgl_stepPosition_t *pos)
256 {
257  if (event == BUTTON_LEFT_PRESSED) {
258  if (context.currentPage > 0) {
259  context.currentPage--;
260  }
261  else {
262  // Drop the event
263  return false;
264  }
265  *pos = BACKWARD_DIRECTION;
266  }
267  else if (event == BUTTON_RIGHT_PRESSED) {
268  if (context.currentPage < (int) (context.nbPages - 1)) {
269  context.currentPage++;
270  }
271  else {
272  // Drop the event
273  return false;
274  }
275  *pos = FORWARD_DIRECTION;
276  }
277  else {
278  if ((event == BUTTON_BOTH_PRESSED) && (context.stepCallback != NULL)) {
279  context.stepCallback();
280  }
281  return false;
282  }
283  return true;
284 }
285 
286 static void reviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
287 {
288  UNUSED(stepCtx);
290 
291  if (!buttonGenericCallback(event, &pos)) {
292  return;
293  }
294 
295  displayReviewPage(pos);
296 }
297 
298 static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
299 {
300  UNUSED(stepCtx);
302 
303  if (!buttonGenericCallback(event, &pos)) {
304  return;
305  }
306 
307  displayStreamingReviewPage(pos);
308 }
309 
310 static void settingsCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
311 {
312  UNUSED(stepCtx);
314 
315  if (!buttonGenericCallback(event, &pos)) {
316  return;
317  }
318 
319  displaySettingsPage(pos, false);
320 }
321 
322 static void infoCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
323 {
324  UNUSED(stepCtx);
326 
327  if (!buttonGenericCallback(event, &pos)) {
328  return;
329  }
330 
331  displayInfoPage(pos);
332 }
333 
334 static void homeCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
335 {
336  UNUSED(stepCtx);
338 
339  if (!buttonGenericCallback(event, &pos)) {
340  return;
341  }
342 
343  displayHomePage(pos);
344 }
345 
346 static void genericChoiceCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
347 {
348  UNUSED(stepCtx);
350 
351  if (!buttonGenericCallback(event, &pos)) {
352  return;
353  }
354 
355  displayChoicePage(pos);
356 }
357 
358 static void statusButtonCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
359 {
360  UNUSED(stepCtx);
361  if (event == BUTTON_BOTH_PRESSED) {
362  if (context.stepCallback != NULL) {
363  context.stepCallback();
364  }
365  }
366 }
367 
368 // callback used for timeout
369 static void statusTickerCallback(void)
370 {
371  if (context.stepCallback != NULL) {
372  context.stepCallback();
373  }
374 }
375 
376 // function used to display the current page in review
377 static void displayReviewPage(nbgl_stepPosition_t pos)
378 {
379  const char *text = NULL;
380  const char *subText = NULL;
381  const nbgl_icon_details_t *icon = NULL;
382 
383  context.stepCallback = NULL;
384 
385  if (context.currentPage == 0) { // title page
386  icon = context.review.icon;
387  text = context.review.reviewTitle;
388  }
389  else if (context.currentPage == (context.nbPages - 2)) { // accept page
390  icon = &C_icon_validate_14;
391  text = "Approve";
392  context.stepCallback = onReviewAccept;
393  }
394  else if (context.currentPage == (context.nbPages - 1)) { // reject page
395  icon = &C_icon_crossmark;
396  text = "Reject";
397  context.stepCallback = onReviewReject;
398  }
399  else if ((context.review.address != NULL)
400  && (context.currentPage == 1)) { // address confirmation and 2nd page
401  text = "Address";
402  subText = context.review.address;
403  }
404  else {
405  uint8_t pairIndex = (context.review.address != NULL) ? (context.currentPage - 2)
406  : (context.currentPage - 1);
407  getPairData(context.review.tagValueList, pairIndex, &text, &subText);
408  }
409 
410  drawStep(pos, icon, text, subText, reviewCallback);
411  nbgl_refresh();
412 }
413 
414 // function used to display the current page in review
415 static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
416 {
417  const char *text = NULL;
418  const char *subText = NULL;
419  const nbgl_icon_details_t *icon = NULL;
420 
421  context.stepCallback = NULL;
422 
423  if (context.type == STREAMING_START_REVIEW_USE_CASE) {
424  if (context.currentPage == 0) { // title page
425  icon = context.review.icon;
426  text = context.review.reviewTitle;
427  }
428  else {
429  nbgl_useCaseSpinner("Processing");
430  onReviewAccept();
431  return;
432  }
433  }
434  else if (context.type == STREAMING_CONTINUE_REVIEW_USE_CASE) {
435  if (context.currentPage < context.review.tagValueList->nbPairs) {
436  getPairData(context.review.tagValueList, context.currentPage, &text, &subText);
437  }
438  else {
439  nbgl_useCaseSpinner("Processing");
440  onReviewAccept();
441  return;
442  }
443  }
444  else {
445  if (context.currentPage == 0) { // accept page
446  icon = &C_icon_validate_14;
447  text = "Approve";
448  context.stepCallback = onReviewAccept;
449  }
450  else { // reject page
451  icon = &C_icon_crossmark;
452  text = "Reject";
453  context.stepCallback = onReviewReject;
454  }
455  }
456 
457  drawStep(pos, icon, text, subText, streamingReviewCallback);
458  nbgl_refresh();
459 }
460 
461 // function used to display the current page in info
462 static void displayInfoPage(nbgl_stepPosition_t pos)
463 {
464  const char *text = NULL;
465  const char *subText = NULL;
466  const nbgl_icon_details_t *icon = NULL;
467 
468  context.stepCallback = NULL;
469 
470  if (context.currentPage < (context.nbPages - 1)) {
471  text = PIC(
472  ((const char *const *) PIC(context.home.infosList->infoTypes))[context.currentPage]);
473  subText = PIC(
474  ((const char *const *) PIC(context.home.infosList->infoContents))[context.currentPage]);
475  }
476  else {
477  icon = &C_icon_back_x;
478  text = "Back";
479  context.stepCallback = startUseCaseHome;
480  }
481 
482  drawStep(pos, icon, text, subText, infoCallback);
483  nbgl_refresh();
484 }
485 
486 // function used to display the current page in settings
487 static void displaySettingsPage(nbgl_stepPosition_t pos, bool toogle_state)
488 {
489  const char *text = NULL;
490  const char *subText = NULL;
491  const nbgl_icon_details_t *icon = NULL;
492 
493  context.stepCallback = NULL;
494 
495  if (context.currentPage < (context.nbPages - 1)) {
496  nbgl_content_t nbgl_content;
497  uint8_t elemIdx;
498 
499  const nbgl_content_t *p_nbgl_content = getContentElemAtIdx(
500  context.home.settingContents, context.currentPage, &elemIdx, &nbgl_content);
501 
502  switch (p_nbgl_content->type) {
503  case TAG_VALUE_LIST:
504  getPairData(&p_nbgl_content->content.tagValueList, elemIdx, &text, &subText);
505  break;
506  case SWITCHES_LIST: {
507  const nbgl_contentSwitch_t *contentSwitch = &((const nbgl_contentSwitch_t *) PIC(
508  p_nbgl_content->content.switchesList.switches))[elemIdx];
509  text = contentSwitch->text;
510  // switch subtext is ignored
511  nbgl_state_t state = contentSwitch->initState;
512  if (toogle_state) {
513  state = (state == ON_STATE) ? OFF_STATE : ON_STATE;
514  }
515  if (state == ON_STATE) {
516  subText = "Enabled";
517  }
518  else {
519  subText = "Disabled";
520  }
521  context.stepCallback = onSettingsAction;
522  break;
523  }
524  case INFOS_LIST:
525  text = ((const char *const *) PIC(
526  p_nbgl_content->content.infosList.infoTypes))[elemIdx];
527  subText = ((const char *const *) PIC(
528  p_nbgl_content->content.infosList.infoContents))[elemIdx];
529  break;
530  default:
531  break;
532  }
533  }
534  else { // last page is for quit
535  icon = &C_icon_back_x;
536  text = "Back";
537  context.stepCallback = startUseCaseHome;
538  }
539 
540  drawStep(pos, icon, text, subText, settingsCallback);
541  nbgl_refresh();
542 }
543 
544 static void startUseCaseHome(void)
545 {
546  if (context.type == SETTINGS_USE_CASE) {
547  context.currentPage = 1;
548  }
549  else if (context.type == INFO_USE_CASE) {
550  context.currentPage = 2;
551  }
552  else {
553  context.currentPage = 0;
554  }
555  context.type = HOME_USE_CASE;
556  context.nbPages = 4;
557 
558  displayHomePage(FORWARD_DIRECTION);
559 }
560 
561 static void startUseCaseInfo(void)
562 {
563  context.type = INFO_USE_CASE;
564  context.nbPages = context.home.infosList->nbInfos + 1; // For back screen
565  context.currentPage = 0;
566 
567  displayInfoPage(FORWARD_DIRECTION);
568 }
569 
570 static void startUseCaseSettingsAtPage(uint8_t initSettingPage)
571 {
572  nbgl_content_t content;
573  const nbgl_content_t *p_content;
574 
575  context.type = SETTINGS_USE_CASE;
576  context.nbPages = 1; // For back screen
577  for (int i = 0; i < context.home.settingContents->nbContents; i++) {
578  p_content = getContentAtIdx(context.home.settingContents, i, &content);
579  context.nbPages += getContentNbElement(p_content);
580  }
581  context.currentPage = initSettingPage;
582 
583  displaySettingsPage(FORWARD_DIRECTION, false);
584 }
585 
586 static void startUseCaseSettings(void)
587 {
588  startUseCaseSettingsAtPage(0);
589 }
590 
591 // function used to display the current page in home
592 static void displayHomePage(nbgl_stepPosition_t pos)
593 {
594  const char *text = NULL;
595  const char *subText = NULL;
596  const nbgl_icon_details_t *icon = NULL;
597 
598  context.stepCallback = NULL;
599 
600  // Handle case where there is no settings
601  if (context.home.settingContents == NULL && context.currentPage == 1) {
602  if (pos & BACKWARD_DIRECTION) {
603  context.currentPage -= 1;
604  }
605  else {
606  context.currentPage += 1;
607  if (context.home.infosList == NULL) {
608  context.currentPage += 1;
609  }
610  }
611  }
612 
613  // Handle case where there is no info
614  if (context.home.infosList == NULL && context.currentPage == 2) {
615  if (pos & BACKWARD_DIRECTION) {
616  context.currentPage -= 1;
617  if (context.home.settingContents == NULL) {
618  context.currentPage -= 1;
619  }
620  }
621  else {
622  context.currentPage += 1;
623  }
624  }
625 
626  switch (context.currentPage) {
627  case 0:
628  icon = context.home.appIcon;
629  if (context.home.tagline != NULL) {
630  text = context.home.tagline;
631  }
632  else {
633  text = context.home.appName;
634  subText = "is ready";
635  }
636  break;
637  case 1:
638  icon = &C_icon_coggle;
639  text = "Settings";
640  context.stepCallback = startUseCaseSettings;
641  break;
642  case 2:
643  icon = &C_icon_certificate;
644  text = "About";
645  context.stepCallback = startUseCaseInfo;
646  break;
647  default:
648  icon = &C_icon_dashboard_x;
649  text = "Quit";
650  context.stepCallback = context.home.quitCallback;
651  break;
652  }
653 
654  drawStep(pos, icon, text, subText, homeCallback);
655  nbgl_refresh();
656 }
657 
658 // function used to display the current page in choice
659 static void displayChoicePage(nbgl_stepPosition_t pos)
660 {
661  const char *text = NULL;
662  const char *subText = NULL;
663  const nbgl_icon_details_t *icon = NULL;
664 
665  context.stepCallback = NULL;
666 
667  // Handle case where there is no icon or subMessage
668  if (context.currentPage == 1
669  && (context.choice.icon == NULL || context.choice.subMessage == NULL)) {
670  if (pos & BACKWARD_DIRECTION) {
671  context.currentPage -= 1;
672  }
673  else {
674  context.currentPage += 1;
675  }
676  }
677 
678  if (context.currentPage == 0) { // title page
679  text = context.choice.message;
680  if (context.choice.icon != NULL) {
681  icon = context.choice.icon;
682  }
683  else {
684  subText = context.choice.subMessage;
685  }
686  }
687  else if (context.currentPage == 1) { // sub-title page
688  // displayed only if there is both icon and submessage
689  text = context.choice.message;
690  subText = context.choice.subMessage;
691  }
692  else if (context.currentPage == 2) { // confirm page
693  icon = &C_icon_validate_14;
694  text = context.choice.confirmText;
695  context.stepCallback = onChoiceAccept;
696  }
697  else { // cancel page
698  icon = &C_icon_crossmark;
699  text = context.choice.cancelText;
700  context.stepCallback = onChoiceReject;
701  }
702 
703  drawStep(pos, icon, text, subText, genericChoiceCallback);
704  nbgl_refresh();
705 }
706 
707 /**********************
708  * GLOBAL FUNCTIONS
709  **********************/
710 
725 void nbgl_useCaseHomeAndSettings(const char *appName,
726  const nbgl_icon_details_t *appIcon,
727  const char *tagline,
728  const uint8_t initSettingPage,
729  const nbgl_genericContents_t *settingContents,
730  const nbgl_contentInfoList_t *infosList,
731  const nbgl_homeAction_t *action,
732  nbgl_callback_t quitCallback)
733 {
734  UNUSED(action); // TODO support it at some point?
735 
736  memset(&context, 0, sizeof(UseCaseContext_t));
737  context.home.appName = appName;
738  context.home.appIcon = appIcon;
739  context.home.tagline = tagline;
740  context.home.settingContents = PIC(settingContents);
741  context.home.infosList = PIC(infosList);
742  context.home.quitCallback = quitCallback;
743 
744  if (initSettingPage != INIT_HOME_PAGE) {
745  startUseCaseSettingsAtPage(initSettingPage);
746  }
747  else {
748  startUseCaseHome();
749  }
750 }
751 
766 void nbgl_useCaseReview(nbgl_operationType_t operationType,
767  const nbgl_contentTagValueList_t *tagValueList,
768  const nbgl_icon_details_t *icon,
769  const char *reviewTitle,
770  const char *reviewSubTitle,
771  const char *finishTitle,
772  nbgl_choiceCallback_t choiceCallback)
773 {
774  UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
775  UNUSED(reviewSubTitle); // TODO dedicated screen for it?
776  UNUSED(finishTitle); // TODO dedicated screen for it?
777 
778  memset(&context, 0, sizeof(UseCaseContext_t));
779  context.type = REVIEW_USE_CASE;
780  context.review.tagValueList = tagValueList;
781  context.review.reviewTitle = reviewTitle;
782  context.review.icon = icon;
783  context.review.onChoice = choiceCallback;
784  context.currentPage = 0;
785  // + 3 because 1 page for title and 2 pages at the end for accept/reject
786  context.nbPages = tagValueList->nbPairs + 3;
787 
788  displayReviewPage(FORWARD_DIRECTION);
789 }
790 
806  const nbgl_contentTagValueList_t *tagValueList,
807  const nbgl_icon_details_t *icon,
808  const char *reviewTitle,
809  const char *reviewSubTitle,
810  const char *finishTitle,
811  nbgl_choiceCallback_t choiceCallback)
812 {
813  return nbgl_useCaseReview(operationType,
814  tagValueList,
815  icon,
816  reviewTitle,
817  reviewSubTitle,
818  finishTitle,
819  choiceCallback);
820 }
821 
838 void nbgl_useCaseAddressReview(const char *address,
839  const nbgl_contentTagValueList_t *additionalTagValueList,
840  const nbgl_icon_details_t *icon,
841  const char *reviewTitle,
842  const char *reviewSubTitle,
843  nbgl_choiceCallback_t choiceCallback)
844 {
845  UNUSED(reviewSubTitle); // TODO dedicated screen for it?
846 
847  memset(&context, 0, sizeof(UseCaseContext_t));
848  context.type = ADDRESS_REVIEW_USE_CASE;
849  context.review.address = address;
850  context.review.reviewTitle = reviewTitle;
851  context.review.icon = icon;
852  context.review.onChoice = choiceCallback;
853  context.currentPage = 0;
854  // + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
855  context.nbPages = 4;
856  if (additionalTagValueList) {
857  memcpy(&context.review.tagValueList,
858  additionalTagValueList,
860  context.nbPages += additionalTagValueList->nbPairs;
861  }
862 
863  displayReviewPage(FORWARD_DIRECTION);
864 }
865 
873 void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
874 {
875  UNUSED(isSuccess); // TODO add icon depending on isSuccess?
876 
877  memset(&context, 0, sizeof(UseCaseContext_t));
878  context.stepCallback = quitCallback;
879  context.currentPage = 0;
880  context.nbPages = 1;
881 
883  .tickerCallback = PIC(statusTickerCallback),
884  .tickerIntervale = 0, // not periodic
885  .tickerValue = 3000 // 3 seconds
886  };
887 
889  SINGLE_STEP, statusButtonCallback, &ticker, message, NULL, BOLD_TEXT1_INFO, false);
890  nbgl_refresh();
891 }
892 
900  nbgl_callback_t quitCallback)
901 {
902  const char *msg;
903  bool isSuccess;
904  switch (reviewStatusType) {
906  msg = "Operation signed";
907  isSuccess = true;
908  break;
910  msg = "Operation rejected";
911  isSuccess = false;
912  break;
914  msg = "Transaction signed";
915  isSuccess = true;
916  break;
918  msg = "Transaction rejected";
919  isSuccess = false;
920  break;
922  msg = "Message signed";
923  isSuccess = true;
924  break;
926  msg = "Message rejected";
927  isSuccess = false;
928  break;
930  msg = "Address verified";
931  isSuccess = true;
932  break;
934  msg = "Verification\ncancelled";
935  isSuccess = false;
936  break;
937  default:
938  return;
939  }
940  nbgl_useCaseStatus(msg, isSuccess, quitCallback);
941 }
942 
956  const nbgl_icon_details_t *icon,
957  const char *reviewTitle,
958  const char *reviewSubTitle,
959  nbgl_choiceCallback_t choiceCallback)
960 {
961  UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
962  UNUSED(reviewSubTitle); // TODO dedicated screen for it?
963 
964  memset(&context, 0, sizeof(UseCaseContext_t));
965  context.type = STREAMING_START_REVIEW_USE_CASE;
966  context.review.reviewTitle = reviewTitle;
967  context.review.icon = icon;
968  context.review.onChoice = choiceCallback;
969  context.currentPage = 0;
970  context.nbPages = 1 + 1; // Start page + trick for review continue
971 
972  displayStreamingReviewPage(FORWARD_DIRECTION);
973 }
974 
987  nbgl_choiceCallback_t choiceCallback,
988  nbgl_callback_t skipCallback)
989 {
990  UNUSED(skipCallback);
991 
992  memset(&context, 0, sizeof(UseCaseContext_t));
993  context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
994  context.review.tagValueList = tagValueList;
995  context.review.onChoice = choiceCallback;
996  context.currentPage = 0;
997  context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
998 
999  displayStreamingReviewPage(FORWARD_DIRECTION);
1000 }
1001 
1013  nbgl_choiceCallback_t choiceCallback)
1014 {
1015  nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL);
1016 }
1017 
1018 void nbgl_useCaseReviewStreamingFinish(const char *finishTitle,
1019  nbgl_choiceCallback_t choiceCallback)
1020 {
1021  UNUSED(finishTitle); // TODO dedicated screen for it?
1022 
1023  memset(&context, 0, sizeof(UseCaseContext_t));
1024  context.type = STREAMING_FINISH_REVIEW_USE_CASE;
1025  context.review.onChoice = choiceCallback;
1026  context.currentPage = 0;
1027  context.nbPages = 2; // 2 pages at the end for accept/reject
1028 
1029  displayStreamingReviewPage(FORWARD_DIRECTION);
1030 }
1031 
1037 void nbgl_useCaseSpinner(const char *text)
1038 {
1039  drawStep(SINGLE_STEP, &C_icon_processing, text, NULL, NULL);
1040  nbgl_refresh();
1041 }
1042 
1043 void nbgl_useCaseChoice(const nbgl_icon_details_t *icon,
1044  const char *message,
1045  const char *subMessage,
1046  const char *confirmText,
1047  const char *cancelText,
1048  nbgl_choiceCallback_t callback)
1049 {
1050  memset(&context, 0, sizeof(UseCaseContext_t));
1051  context.type = CHOICE_USE_CASE;
1052  context.choice.icon = icon;
1053  context.choice.message = message;
1054  context.choice.subMessage = subMessage;
1055  context.choice.confirmText = confirmText;
1056  context.choice.cancelText = cancelText;
1057  context.choice.onChoice = callback;
1058  context.currentPage = 0;
1059  context.nbPages = 1 + 1 + 2; // 2 pages at the end for confirm/cancel
1060 
1061  displayChoicePage(FORWARD_DIRECTION);
1062 };
1063 
1064 #endif // HAVE_SE_TOUCH
1065 #endif // NBGL_USE_CASE
@ SWITCHES_LIST
list of switches with descriptions
Definition: nbgl_content.h:348
@ INFOS_LIST
list of infos with titles
Definition: nbgl_content.h:349
@ TAG_VALUE_LIST
list of tag/value pairs
Definition: nbgl_content.h:345
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
Definition: nbgl_content.h:180
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_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
Definition: nbgl_obj.c:1561
nbgl_buttonEvent_t
Definition: nbgl_obj.h:182
@ BUTTON_BOTH_PRESSED
Sent when both buttons are released.
Definition: nbgl_obj.h:189
@ BUTTON_LEFT_PRESSED
Sent when Left button is released.
Definition: nbgl_obj.h:183
@ BUTTON_RIGHT_PRESSED
Send when Right button is released.
Definition: nbgl_obj.h:184
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
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:56
#define GET_POS_OF_STEP(_step, _nb_steps)
Definition: nbgl_step.h:30
@ SINGLE_STEP
single step flow
Definition: nbgl_step.h:63
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:79
#define FORWARD_DIRECTION
When the flow is navigated from last to first step.
Definition: nbgl_step.h:70
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:72
nbgl_state_t
to represent a boolean state.
Definition: nbgl_types.h:160
@ ON_STATE
Definition: nbgl_types.h:162
@ OFF_STATE
Definition: nbgl_types.h:161
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.
void(* nbgl_callback_t)(void)
prototype of generic callback function
uint32_t nbgl_operationType_t
This mask is used to describe the type of operation to review with additional options It is a mask of...
void nbgl_useCaseReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_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)
void(* nbgl_choiceCallback_t)(bool confirm)
prototype of choice callback function
void nbgl_useCaseReviewStreamingFinish(const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseSpinner(const char *text)
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
#define INIT_HOME_PAGE
Value to pass to nbgl_useCaseHomeAndSettings() initSettingPage parameter to initialize the use case o...
Definition: nbgl_use_case.h:97
void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback, nbgl_callback_t skipCallback)
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_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)
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
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)
This structure contains info to build a centered (vertically and horizontally) area,...
Definition: nbgl_content.h:57
const char * text2
second text (can be null)
Definition: nbgl_content.h:59
const char * text1
first text (can be null)
Definition: nbgl_content.h:58
bool onTop
if set to true, align only horizontally
Definition: nbgl_content.h:64
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
Definition: nbgl_content.h:65
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
Definition: nbgl_content.h:63
This structure contains data to build a INFOS_LIST content.
Definition: nbgl_content.h:268
uint8_t nbInfos
number of elements in infoTypes and infoContents array
Definition: nbgl_content.h:274
const char *const * infoContents
array of contents of infos (in black)
Definition: nbgl_content.h:270
const char *const * infoTypes
array of types of infos (in black/bold)
Definition: nbgl_content.h:269
This structure contains info to build a switch (on the right) with a description (on the left),...
Definition: nbgl_content.h:246
const char * text
main text for the switch
Definition: nbgl_content.h:247
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:251
nbgl_state_t initState
initial state of the switch
Definition: nbgl_content.h:250
This structure contains a list of [tag,value] pairs.
Definition: nbgl_content.h:185
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
Definition: nbgl_content.h:187
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
Definition: nbgl_content.h:188
This structure contains a [tag,value] pair.
Definition: nbgl_content.h:148
const char * value
string giving the value name
Definition: nbgl_content.h:150
const char * item
string giving the tag name
Definition: nbgl_content.h:149
This structure contains data to build a content.
Definition: nbgl_content.h:374
nbgl_content_u content
Definition: nbgl_content.h:376
nbgl_contentActionCallback_t contentActionCallback
callback to be called when an action on an object occurs
Definition: nbgl_content.h:378
nbgl_contentType_t type
type of page content in the content union
Definition: nbgl_content.h:375
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.
uint8_t nbSwitches
number of elements in switches and tokens array
Definition: nbgl_content.h:262
const nbgl_contentSwitch_t * switches
array of switches (nbSwitches items)
Definition: nbgl_content.h:261
nbgl_contentInfoList_t infosList
INFOS_LIST type
Definition: nbgl_content.h:366
nbgl_contentTagValueList_t tagValueList
TAG_VALUE_LIST type
Definition: nbgl_content.h:362
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
Definition: nbgl_content.h:365
unsigned char uint8_t
Definition: usbd_conf.h:53
signed char int8_t
Definition: usbd_conf.h:49