Skip to content

Commit

Permalink
Add missing API or feature for Nano on NBGL
Browse files Browse the repository at this point in the history
  • Loading branch information
cedelavergne-ledger committed Jan 3, 2025
1 parent a2be76c commit 306ee92
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 46 deletions.
2 changes: 2 additions & 0 deletions lib_nbgl/src/nbgl_use_case.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*********************/
#include <string.h>
#include <stdio.h>
#include "nbgl_page.h"
#include "nbgl_debug.h"
#include "nbgl_use_case.h"
#include "glyphs.h"
Expand Down Expand Up @@ -3056,6 +3057,7 @@ void nbgl_useCaseReviewBlindSigning(nbgl_operationType_t operationT

blindSigningWarning();
}

/**
* @brief Draws a flow of pages of a light review. Navigation operates with either swipe or
* navigation keys at bottom right. The last page contains a button/footer with the given
Expand Down
258 changes: 212 additions & 46 deletions lib_nbgl/src/nbgl_use_case_nanos.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct ReviewContext_s {
const nbgl_contentTagValueList_t *tagValueList;
const nbgl_icon_details_t *icon;
const char *reviewTitle;
const char *reviewSubTitle;
const char *address; // for address confirmation review
} ReviewContext_t;

Expand All @@ -54,6 +55,7 @@ typedef struct HomeContext_s {
typedef enum {
NONE_USE_CASE,
REVIEW_USE_CASE,
REVIEW_BLIND_SIGN_USE_CASE,
ADDRESS_REVIEW_USE_CASE,
STREAMING_START_REVIEW_USE_CASE,
STREAMING_CONTINUE_REVIEW_USE_CASE,
Expand Down Expand Up @@ -376,17 +378,24 @@ static void statusTickerCallback(void)
// function used to display the current page in review
static void displayReviewPage(nbgl_stepPosition_t pos)
{
const char *text = NULL;
const char *subText = NULL;
const nbgl_icon_details_t *icon = NULL;
uint8_t reviewPage = 0;
uint8_t pairIndex = 0;
const char *text = NULL;
const char *subText = NULL;
const nbgl_icon_details_t *icon = NULL;

context.stepCallback = NULL;

if (context.currentPage == 0) { // title page
icon = context.review.icon;
text = context.review.reviewTitle;
// Determine the 1st page to display tag/values
reviewPage = 1; // 1st page is for title
if (context.type == REVIEW_BLIND_SIGN_USE_CASE) {
reviewPage++; // 2nd page is for warning
}
if (context.review.reviewSubTitle) {
reviewPage++; // 3rd page is for subtitle
}
else if (context.currentPage == (context.nbPages - 2)) { // accept page
// Determine which page to display
if (context.currentPage == (context.nbPages - 2)) { // accept page
icon = &C_icon_validate_14;
text = "Approve";
context.stepCallback = onReviewAccept;
Expand All @@ -396,14 +405,50 @@ static void displayReviewPage(nbgl_stepPosition_t pos)
text = "Reject";
context.stepCallback = onReviewReject;
}
else if ((context.review.address != NULL)
&& (context.currentPage == 1)) { // address confirmation and 2nd page
else if (context.currentPage < reviewPage) {
// header page(s)
switch (context.currentPage) {
case 0:
if (context.type == REVIEW_BLIND_SIGN_USE_CASE) {
// warning page
icon = &C_icon_warning;
text = "Blind\nsigning";
}
else {
// title page
icon = context.review.icon;
text = context.review.reviewTitle;
}
break;
case 1:
if (context.type == REVIEW_BLIND_SIGN_USE_CASE) {
// title page
icon = context.review.icon;
text = context.review.reviewTitle;
}
else {
// subtitle page
text = context.review.reviewSubTitle;
}
break;
case 2:
// subtitle page
text = context.review.reviewSubTitle;
break;
default:
break;
}
}
else if ((context.review.address != NULL) && (context.currentPage == reviewPage)) {
// address confirmation and 2nd page
text = "Address";
subText = context.review.address;
}
else {
uint8_t pairIndex = (context.review.address != NULL) ? (context.currentPage - 2)
: (context.currentPage - 1);
pairIndex = context.currentPage - reviewPage;
if (context.review.address != NULL) {
pairIndex--;
}
getPairData(context.review.tagValueList, pairIndex, &text, &subText);
}

Expand All @@ -414,16 +459,35 @@ static void displayReviewPage(nbgl_stepPosition_t pos)
// function used to display the current page in review
static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
{
const char *text = NULL;
const char *subText = NULL;
const nbgl_icon_details_t *icon = NULL;
uint8_t reviewPage = 0;
const char *text = NULL;
const char *subText = NULL;
const nbgl_icon_details_t *icon = NULL;

context.stepCallback = NULL;

if (context.type == STREAMING_START_REVIEW_USE_CASE) {
if (context.currentPage == 0) { // title page
icon = context.review.icon;
text = context.review.reviewTitle;
// Determine the 1st page to display tag/values
reviewPage = 1; // 1st page is for title
if (context.review.reviewSubTitle) {
reviewPage++; // 3rd page is for subtitle
}
// Determine which page to display
if (context.currentPage < reviewPage) {
// header page(s)
switch (context.currentPage) {
case 0:
// title page
icon = context.review.icon;
text = context.review.reviewTitle;
break;
case 1:
// subtitle page
text = context.review.reviewSubTitle;
break;
default:
break;
}
}
else {
nbgl_useCaseSpinner("Processing");
Expand Down Expand Up @@ -704,6 +768,37 @@ static void displayChoicePage(nbgl_stepPosition_t pos)
nbgl_refresh();
}

// function to factorize code for all simple reviews
static void useCaseReview(ContextType_t type,
const nbgl_contentTagValueList_t *tagValueList,
const nbgl_icon_details_t *icon,
const char *reviewTitle,
const char *reviewSubTitle,
const char *finishTitle,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(finishTitle); // TODO dedicated screen for it?

memset(&context, 0, sizeof(UseCaseContext_t));
context.type = type;
context.review.tagValueList = tagValueList;
context.review.reviewTitle = reviewTitle;
context.review.reviewSubTitle = reviewSubTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
// + 3 because 1 page for title and 2 pages at the end for accept/reject
context.nbPages = tagValueList->nbPairs + 3;
if (type == REVIEW_BLIND_SIGN_USE_CASE) {
context.nbPages++; // 1 page for warning
}
if (reviewSubTitle) {
context.nbPages++; // 1 page for subtitle page
}

displayReviewPage(FORWARD_DIRECTION);
}

/**********************
* GLOBAL FUNCTIONS
**********************/
Expand Down Expand Up @@ -771,21 +866,93 @@ void nbgl_useCaseReview(nbgl_operationType_t operationType,
const char *finishTitle,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
UNUSED(reviewSubTitle); // TODO dedicated screen for it?
UNUSED(finishTitle); // TODO dedicated screen for it?
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?

useCaseReview(REVIEW_USE_CASE,
tagValueList,
icon,
reviewTitle,
reviewSubTitle,
finishTitle,
choiceCallback);
}

memset(&context, 0, sizeof(UseCaseContext_t));
context.type = REVIEW_USE_CASE;
context.review.tagValueList = tagValueList;
context.review.reviewTitle = reviewTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
// + 3 because 1 page for title and 2 pages at the end for accept/reject
context.nbPages = tagValueList->nbPairs + 3;
/**
* @brief Draws a flow of pages of a review. Navigation operates with either swipe or navigation
* keys at bottom right. The last page contains a long-press button with the given finishTitle and
* the given icon.
* @note All tag/value pairs are provided in the API and the number of pages is automatically
* computed, the last page being a long press one
*
* @param operationType type of operation (Operation, Transaction, Message)
* @param tagValueList list of tag/value pairs
* @param icon icon used on first and last review page
* @param reviewTitle string used in the first review page
* @param reviewSubTitle string to set under reviewTitle (can be NULL)
* @param finishTitle string used in the last review page
* @param dummy inconsistent parameter on Nano devices (ignored)
* @param choiceCallback callback called when operation is accepted (param is true) or rejected
* (param is false)
*/
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 *dummy,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
UNUSED(dummy);

useCaseReview(REVIEW_USE_CASE,
tagValueList,
icon,
reviewTitle,
reviewSubTitle,
finishTitle,
choiceCallback);
}

displayReviewPage(FORWARD_DIRECTION);
/**
* @brief Draws a flow of pages of a blind-signing review. The review is preceded by a warning page
*
* Navigation operates with either swipe or navigation
* keys at bottom right. The last page contains a long-press button with the given finishTitle and
* the given icon.
* @note All tag/value pairs are provided in the API and the number of pages is automatically
* computed, the last page being a long press one
*
* @param operationType type of operation (Operation, Transaction, Message)
* @param tagValueList list of tag/value pairs
* @param icon icon used on first and last review page
* @param reviewTitle string used in the first review page
* @param reviewSubTitle string to set under reviewTitle (can be NULL)
* @param finishTitle string used in the last review page
* @param dummy inconsistent parameter on Nano devices (ignored)
* @param choiceCallback callback called when operation is accepted (param is true) or rejected
* (param is false)
*/
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 *dummy,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
UNUSED(dummy);

useCaseReview(REVIEW_BLIND_SIGN_USE_CASE,
tagValueList,
icon,
reviewTitle,
reviewSubTitle,
finishTitle,
choiceCallback);
}

/**
Expand Down Expand Up @@ -842,15 +1009,14 @@ void nbgl_useCaseAddressReview(const char *address,
const char *reviewSubTitle,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(reviewSubTitle); // TODO dedicated screen for it?

memset(&context, 0, sizeof(UseCaseContext_t));
context.type = ADDRESS_REVIEW_USE_CASE;
context.review.address = address;
context.review.reviewTitle = reviewTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
context.type = ADDRESS_REVIEW_USE_CASE;
context.review.address = address;
context.review.reviewTitle = reviewTitle;
context.review.reviewSubTitle = reviewSubTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
// + 4 because 1 page for title, 1 for address and 2 pages at the end for approve/reject
context.nbPages = 4;
if (additionalTagValueList) {
Expand Down Expand Up @@ -958,16 +1124,16 @@ void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType,
const char *reviewSubTitle,
nbgl_choiceCallback_t choiceCallback)
{
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?
UNUSED(reviewSubTitle); // TODO dedicated screen for it?
UNUSED(operationType); // TODO adapt accept and reject text depending on this value?

memset(&context, 0, sizeof(UseCaseContext_t));
context.type = STREAMING_START_REVIEW_USE_CASE;
context.review.reviewTitle = reviewTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
context.nbPages = 1 + 1; // Start page + trick for review continue
context.type = STREAMING_START_REVIEW_USE_CASE;
context.review.reviewTitle = reviewTitle;
context.review.reviewSubTitle = reviewSubTitle;
context.review.icon = icon;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
context.nbPages = 1 + 1; // Start page + trick for review continue

displayStreamingReviewPage(FORWARD_DIRECTION);
}
Expand Down

0 comments on commit 306ee92

Please sign in to comment.