Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nano NBGL improvements (support Skip & truncate titles) level 22 #874

Merged
merged 2 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion lib_nbgl/src/nbgl_step.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,31 @@ static void displayTextPage(StepContext_t *ctx, uint8_t textPage)
nbgl_layoutAddText(ctx->layout, ctx->textContext.txtStart, txt, ctx->textContext.style);
}
else {
SPRINTF(ctx->textContext.tmpString,
char intermediateString[36]; // a bit bigger but we know that one line cannot contain
// more than 23 chars
SPRINTF(intermediateString,
"%s (%d/%d)",
ctx->textContext.txtStart,
ctx->textContext.currentPage + 1,
ctx->textContext.nbPages);
// truncate title to fit in one line, if necessary
if (nbgl_getTextNbLinesInWidth(BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp,
intermediateString,
AVAILABLE_WIDTH,
false)
> 1) {
nbgl_textReduceOnNbLines(BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp,
intermediateString,
AVAILABLE_WIDTH,
1,
ctx->textContext.tmpString,
TMP_STRING_MAX_LEN);
}
else {
// simply copy
memcpy(ctx->textContext.tmpString, intermediateString, TMP_STRING_MAX_LEN - 1);
ctx->textContext.tmpString[TMP_STRING_MAX_LEN - 1] = 0;
}
nbgl_layoutAddText(
ctx->layout, ctx->textContext.tmpString, txt, ctx->textContext.style);
}
Expand Down
71 changes: 64 additions & 7 deletions lib_nbgl/src/nbgl_use_case_nanos.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ typedef struct ReviewContext_s {
const nbgl_icon_details_t *icon;
const char *reviewTitle;
const char *reviewSubTitle;
const char *address; // for address confirmation review
const char *address; // for address confirmation review
nbgl_callback_t skipCallback; // callback provided by used
bool dataDisplay; // set to true if the current step is a tag/value pair
uint8_t dataDirection; // used to know whether the skip page is reached from back or forward
} ReviewContext_t;

typedef struct ChoiceContext_s {
Expand Down Expand Up @@ -569,11 +572,63 @@ static void reviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
displayReviewPage(pos);
}

static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
// this is the callback used when button action on the "skip" page
static void buttonSkipCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
{
UNUSED(stepCtx);
nbgl_stepPosition_t pos;

if (event == BUTTON_LEFT_PRESSED) {
if ((context.review.dataDirection == BACKWARD_DIRECTION) && (context.currentPage > 0)) {
context.currentPage--;
}
pos = BACKWARD_DIRECTION;
}
else if (event == BUTTON_RIGHT_PRESSED) {
if ((context.review.dataDirection == FORWARD_DIRECTION)
&& (context.currentPage < (int) (context.nbPages - 1))) {
context.currentPage++;
}
pos = FORWARD_DIRECTION;
}
else if (event == BUTTON_BOTH_PRESSED) {
context.review.skipCallback();
return;
}
else {
return;
}
displayStreamingReviewPage(pos);
}

static void streamingReviewCallback(nbgl_step_t stepCtx, nbgl_buttonEvent_t event)
{
nbgl_stepPosition_t pos;
UNUSED(stepCtx);

// if skippable, draw an intermediate page
if ((context.review.skipCallback != NULL) && (context.review.dataDisplay == true)) {
if (event == BUTTON_LEFT_PRESSED) {
context.review.dataDirection = BACKWARD_DIRECTION;
}
else if (event == BUTTON_RIGHT_PRESSED) {
context.review.dataDirection = FORWARD_DIRECTION;
}
else {
return;
}
// this is not a tag/value
context.review.dataDisplay = false;
nbgl_stepDrawText(FORWARD_DIRECTION | BACKWARD_DIRECTION | NEITHER_FIRST_NOR_LAST_STEP,
buttonSkipCallback,
NULL,
"Press right to continue message.\nDouble-press to skip",
NULL,
REGULAR_INFO,
false);
nbgl_refresh();
return;
}
if (!buttonGenericCallback(event, &pos)) {
return;
}
Expand Down Expand Up @@ -766,8 +821,8 @@ static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
uint8_t titleIndex = 255;
uint8_t subIndex = 255;

context.stepCallback = NULL;

context.stepCallback = NULL;
context.review.dataDisplay = false;
switch (context.type) {
case STREAMING_START_REVIEW_USE_CASE:
case STREAMING_BLIND_SIGN_START_REVIEW_USE_CASE:
Expand Down Expand Up @@ -818,6 +873,7 @@ static void displayStreamingReviewPage(nbgl_stepPosition_t pos)
onReviewAccept();
return;
}
context.review.dataDisplay = true;
getPairData(context.review.tagValueList, context.currentPage, &text, &subText);
break;

Expand Down Expand Up @@ -2047,20 +2103,21 @@ void nbgl_useCaseReviewStreamingBlindSigningStart(nbgl_operationType_t ope
* @param tagValueList list of tag/value pairs
* @param choiceCallback callback called when more operation data are needed (param is true) or
* operation is rejected (param is false)
* @param skipCallback unused yet on Nano.
* @param skipCallback callback called when skip button is pressed (if operationType has the @ref
* SKIPPABLE_OPERATION in @ref nbgl_useCaseReviewStreamingStart)
* @ref nbgl_useCaseReviewStreamingFinish shall then be called.
*/
void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList,
nbgl_choiceCallback_t choiceCallback,
nbgl_callback_t skipCallback)
{
UNUSED(skipCallback);

memset(&context, 0, sizeof(UseCaseContext_t));
context.type = STREAMING_CONTINUE_REVIEW_USE_CASE;
context.review.tagValueList = tagValueList;
context.review.onChoice = choiceCallback;
context.currentPage = 0;
context.nbPages = tagValueList->nbPairs + 1; // data + trick for review continue
context.review.skipCallback = skipCallback;

displayStreamingReviewPage(FORWARD_DIRECTION);
}
Expand Down