From f6b64ae54da01bcf8766d4c672a7664689ccbd75 Mon Sep 17 00:00:00 2001 From: Nicolas Roggeman Date: Wed, 22 May 2024 10:05:33 +0200 Subject: [PATCH] Add possible skipping when using nbgl_useCaseReviewStreamingXXX() functions --- lib_nbgl/include/nbgl_use_case.h | 41 +++++++++++++++++---- lib_nbgl/src/nbgl_layout.c | 14 +------- lib_nbgl/src/nbgl_page.c | 2 +- lib_nbgl/src/nbgl_use_case.c | 58 ++++++++++++++++++++++++++---- lib_nbgl/src/nbgl_use_case_nanos.c | 34 ++++++++++++++++-- 5 files changed, 119 insertions(+), 30 deletions(-) diff --git a/lib_nbgl/include/nbgl_use_case.h b/lib_nbgl/include/nbgl_use_case.h index 6751d9938..0511c38ae 100644 --- a/lib_nbgl/include/nbgl_use_case.h +++ b/lib_nbgl/include/nbgl_use_case.h @@ -145,9 +145,9 @@ typedef struct { } nbgl_genericContents_t; typedef struct { - const char *text; - const nbgl_icon_details_t *icon; - nbgl_callback_t callback; + const char *text; ///< text to use in action button in Home page + const nbgl_icon_details_t *icon; ///< icon to use in action button in Home page + nbgl_callback_t callback; ///< function to call when action button is touched in Home page } nbgl_homeAction_t; /** @@ -155,10 +155,33 @@ typedef struct { * */ typedef enum { - TYPE_TRANSACTION = 0, // For operations transferring a coin or taken from an account to another - TYPE_MESSAGE, // For operations signing a message that will not be broadcast on the blockchain - TYPE_OPERATION, // For other types of operation (generic type) -} nbgl_operationType_t; + TYPE_TRANSACTION + = 0, ///< For operations transferring a coin or taken from an account to another + TYPE_MESSAGE, ///< For operations signing a message that will not be broadcast on the + ///< blockchain + TYPE_OPERATION ///< For other types of operation (generic type) +} nbgl_opType_t; + +/** + * @brief This is to use in @ref nbgl_operationType_t when the operation is skippable. + * This is used + * + */ +#define SKIPPABLE_OPERATION (1 << 4) + +/** + * @brief This is to use in @ref nbgl_operationType_t when the operation is "blind" + * This is used to indicate a warning with a top-right button in review first & last page + * + */ +#define BLIND_OPERATION (1 << 5) + +/** + * @brief This mask is used to describe the type of operation to review with additional options + * It is a mask of @ref nbgl_opType_t [| @ref SKIPPABLE_OPERATION] [| @ref BLIND_OPERATION] + * + */ +typedef uint32_t nbgl_operationType_t; /** * @brief The different types of review status @@ -220,6 +243,10 @@ void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback); +void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList, + nbgl_choiceCallback_t choiceCallback, + nbgl_callback_t skipCallback); + void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback); diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 235af5efc..76d9d92b6 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -2378,18 +2378,6 @@ int nbgl_layoutAddHeader(nbgl_layout_t *layout, const nbgl_layoutHeader_t *heade = (nbgl_obj_t *) textArea; layoutInt->headerContainer->nbChildren++; layoutInt->headerContainer->obj.area.height = textArea->obj.area.height; - - // create vertical line separating texts - separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer); - separationLine->lineColor = LIGHT_GRAY; - separationLine->obj.area.width = 1; - separationLine->obj.area.height = layoutInt->headerContainer->obj.area.height; - separationLine->direction = VERTICAL; - separationLine->thickness = 1; - separationLine->obj.alignment = MID_LEFT; - separationLine->obj.alignTo = (nbgl_obj_t *) textArea; - separationLine->obj.alignmentMarginX = -1; - layoutInt->headerContainer->obj.area.height = textArea->obj.area.height; break; } default: @@ -2550,7 +2538,7 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_ separationLine->thickness = 1; separationLine->obj.alignment = MID_LEFT; separationLine->obj.alignTo = (nbgl_obj_t *) textArea; - separationLine->obj.alignmentMarginY = -1; + separationLine->obj.alignmentMarginX = -1; break; } case FOOTER_TEXT_AND_NAV: { diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index 4db978475..7d4953a18 100644 --- a/lib_nbgl/src/nbgl_page.c +++ b/lib_nbgl/src/nbgl_page.c @@ -533,7 +533,7 @@ nbgl_page_t *nbgl_pageDrawGenericContentExt(nbgl_layoutTouchCallback_t onA if (nav->skipText != NULL) { nbgl_layoutHeader_t headerDesc = {.type = HEADER_RIGHT_TEXT, - .separationLine = true, + .separationLine = false, .rightText.text = nav->skipText, .rightText.token = nav->skipToken, .rightText.tuneId = nav->tuneId}; diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c index 11281b897..ad985c719 100644 --- a/lib_nbgl/src/nbgl_use_case.c +++ b/lib_nbgl/src/nbgl_use_case.c @@ -128,6 +128,7 @@ typedef struct { typedef struct { nbgl_operationType_t operationType; nbgl_choiceCallback_t choiceCallback; + nbgl_callback_t skipCallback; const nbgl_icon_details_t *icon; uint8_t stepPageNb; } nbgl_reviewStreamingContext_t; @@ -393,6 +394,8 @@ static void prepareReviewLightLastPage(nbgl_contentInfoButton_t *infoButton, static const char *getRejectReviewText(nbgl_operationType_t operationType) { #ifdef TARGET_STAX + // clear skip and blind bits) + operationType &= ~(SKIPPABLE_OPERATION | BLIND_OPERATION); if (operationType == TYPE_TRANSACTION) { return "Reject transaction"; } @@ -427,7 +430,7 @@ static void pageModalCallback(int token, uint8_t index) else if (token == SKIP_TOKEN) { if (index == 0) { // display the last forward only review page, whatever it is - displayReviewPage(LAST_PAGE_FOR_REVIEW, true); + displayGenericContextPage(LAST_PAGE_FOR_REVIEW, true); } else { // display background, which should be the page where skip has been touched @@ -907,9 +910,17 @@ static void displayGenericContextPage(uint8_t pageIdx, bool forceFullRefresh) bool flag; const nbgl_content_t *p_content = NULL; - if ((navType == STREAMING_NAV) && (pageIdx >= bundleNavContext.reviewStreaming.stepPageNb)) { - bundleNavReviewStreamingChoice(true); - return; + if (navType == STREAMING_NAV) { + if (pageIdx == LAST_PAGE_FOR_REVIEW) { + if (bundleNavContext.reviewStreaming.skipCallback != NULL) { + bundleNavContext.reviewStreaming.skipCallback(); + } + return; + } + else if (pageIdx >= bundleNavContext.reviewStreaming.stepPageNb) { + bundleNavReviewStreamingChoice(true); + return; + } } if (navInfo.activePage == pageIdx) { @@ -1441,7 +1452,8 @@ static void bundleNavReviewAskRejectionConfirmation(nbgl_operationType_t operati { const char *title; const char *confirmText; - + // clear skip and blind bits) + operationType &= ~(SKIPPABLE_OPERATION | BLIND_OPERATION); if (operationType == TYPE_TRANSACTION) { title = "Reject transaction?"; confirmText = "Go back to transaction"; @@ -2605,14 +2617,19 @@ void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, * @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 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_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, - nbgl_choiceCallback_t choiceCallback) +void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList, + nbgl_choiceCallback_t choiceCallback, + nbgl_callback_t skipCallback) { // Should follow a call to nbgl_useCaseReviewStreamingStart memset(&genericContext, 0, sizeof(genericContext)); bundleNavContext.reviewStreaming.choiceCallback = choiceCallback; + bundleNavContext.reviewStreaming.skipCallback = skipCallback; // memorize context onChoice = bundleNavReviewStreamingChoice; @@ -2635,10 +2652,37 @@ void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagVa prepareNavInfo(true, NBGL_NO_PROGRESS_INDICATOR, getRejectReviewText(bundleNavContext.reviewStreaming.operationType)); + // if the operation is skippable + if (bundleNavContext.reviewStreaming.operationType & SKIPPABLE_OPERATION) { +#ifdef TARGET_STAX + navInfo.skipText = "Skip >>"; + navInfo.navWithTap.quitText = "Reject"; +#else + navInfo.progressIndicator = false; + navInfo.skipText = "Skip"; +#endif + navInfo.skipToken = SKIP_TOKEN; + } displayGenericContextPage(0, true); } +/** + * @brief Continue drawing the flow of pages of a review. + * @note This should be called after a call to nbgl_useCaseReviewStreamingStart and can be followed + * by others calls to nbgl_useCaseReviewStreamingContinue and finally to + * nbgl_useCaseReviewStreamingFinish. + * + * @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) + */ +void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, + nbgl_choiceCallback_t choiceCallback) +{ + nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL); +} + /** * @brief finish drawing the flow of pages of a review. * @note This should be called after a call to nbgl_useCaseReviewStreamingContinue. diff --git a/lib_nbgl/src/nbgl_use_case_nanos.c b/lib_nbgl/src/nbgl_use_case_nanos.c index e62d348cc..0b821c461 100644 --- a/lib_nbgl/src/nbgl_use_case_nanos.c +++ b/lib_nbgl/src/nbgl_use_case_nanos.c @@ -972,9 +972,23 @@ void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, displayStreamingReviewPage(FORWARD_DIRECTION); } -void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, - nbgl_choiceCallback_t choiceCallback) +/** + * @brief Continue drawing the flow of pages of a review. + * @note This should be called after a call to nbgl_useCaseReviewStreamingStart and can be followed + * by others calls to nbgl_useCaseReviewStreamingContinue and finally to + * nbgl_useCaseReviewStreamingFinish. + * + * @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. + */ +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; @@ -985,6 +999,22 @@ void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagVa displayStreamingReviewPage(FORWARD_DIRECTION); } +/** + * @brief Continue drawing the flow of pages of a review. + * @note This should be called after a call to nbgl_useCaseReviewStreamingStart and can be followed + * by others calls to nbgl_useCaseReviewStreamingContinue and finally to + * nbgl_useCaseReviewStreamingFinish. + * + * @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) + */ +void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, + nbgl_choiceCallback_t choiceCallback) +{ + nbgl_useCaseReviewStreamingContinueExt(tagValueList, choiceCallback, NULL); +} + void nbgl_useCaseReviewStreamingFinish(const char *finishTitle, nbgl_choiceCallback_t choiceCallback) {