diff --git a/lib_nbgl/doc/mainpage.dox b/lib_nbgl/doc/mainpage.dox
index 926e24936..5bdaad758 100644
--- a/lib_nbgl/doc/mainpage.dox
+++ b/lib_nbgl/doc/mainpage.dox
@@ -1,10 +1,10 @@
#ifdef HAVE_SE_TOUCH
-/** @page nbgl_mainpage New BOLOS Graphic API for Stax
+/** @page nbgl_mainpage New BOLOS Graphic API for Stax/Flex
@section nbgl_mainpage_intro Introduction
This documentation describes the different interfaces of NBGL, the library that
-is targeted to be integrated in Stax product.
+is targeted to be integrated in Stax or Flex product.
NBGL Engine is responsible for constructing screens and handling Touchscreen input.
diff --git a/lib_nbgl/doc/nbgl_use_case.dox b/lib_nbgl/doc/nbgl_use_case.dox
index 53b2c96ac..78391eaa0 100644
--- a/lib_nbgl/doc/nbgl_use_case.dox
+++ b/lib_nbgl/doc/nbgl_use_case.dox
@@ -51,8 +51,7 @@ A few APIs are available to draw typical Use-Cases, such as:
- @ref nbgl_useCaseReviewLight() to draw the pages of a transaction review with a simple button confirmation, when all info are available from the beginning (see @subpage use_case_review_light)
- @ref nbgl_useCaseReviewStreamingStart() to draw the pages of a regular coin transaction review, when all info are not available from the beginning (see @subpage use_case_review_streaming)
- for address verification:
- - @ref nbgl_useCaseAddressConfirmation() to draw an address confirmation page, with a possibility to see it as QR Code (see @subpage use_case_addr_confirm)
- - @ref nbgl_useCaseAddressConfirmationExt() to draw an address confirmation page, with a possibility to see it as QR Code and some extra tag/value pairs (see @subpage use_case_addr_confirm_ext)
+ - @ref nbgl_useCaseAddressReview() to draw an address confirmation page, with a possibility to see it as QR Code and some extra tag/value pairs (see @subpage use_case_addr_review)
- for keypad:
- @ref nbgl_useCaseKeypadPIN() to draw a default keypad implementation with hidden digits (see @subpage use_case_keypad)
- @ref nbgl_useCaseKeypadDigits() to draw a default keypad implementation, showing digits (see @subpage use_case_keypad)
@@ -69,6 +68,9 @@ Some APIs have also been kept for backward compatibility, and for some rare case
- @ref nbgl_useCaseReviewStart() to draw the cover page of a review (initial page, without data)
- @ref nbgl_useCaseStaticReview() to draw the data pages of a regular review, when all info are available from the beginning (all pages but the cover one)
- @ref nbgl_useCaseRegularReview() to draw the data pages of a regular review (all pages but the cover one)
+- for address verification:
+ - @ref nbgl_useCaseAddressConfirmation() to draw an address confirmation page, with a possibility to see it as QR Code
+ - @ref nbgl_useCaseAddressConfirmationExt() to draw an address confirmation page, with a possibility to see it as QR Code and some extra tag/value pairs
- for rare reviews:
- @ref nbgl_useCaseForwardOnlyReview() to draw the pages of a forward-only review (without back key)
- @ref nbgl_useCaseViewDetails() to draw the pages displaying the full value of a given long data of a review
@@ -155,6 +157,22 @@ void appMain(void) {
}
@endcode
+@subsubsection use_case_home_settings_with_action Home & Settings screen with action button Use Case
+
+\image{inline} html UseCase-HomeAction.png "caption" height=300
+
+For some rare applications, one may need an action button in the Home screen, to perform either:
+
+- The main action of the Application
+- Or an side-action, as to display an address
+
+The \b action argument of @ref nbgl_useCaseHomeAndSettings() can be used for that. This structure (@ref nbgl_homeAction_t)
+enables to specify:
+
+- A text & an icon for the button
+- A function to be called when the button is touched
+- The type of button (either @ref STRONG_HOME_ACTION for main action, in black, or @ref SOFT_HOME_ACTION for side action, in white)
+
@subsection use_case_confirm Confirmation Use Case
\image{inline} html UseCase-Confirm.png "caption" height=300
@@ -447,54 +465,16 @@ void staticReview(void) {
}
@endcode
-@subsection use_case_addr_confirm Address Confirmation Use Case
-
-\image{inline} html UseCase-AddressConfirmation.png "caption" height=300
-
-When an address needs to be confirmed, it can be displayed in a Address Confirmation Use Case, at first as simple page with
-the raw address (as text) and a black button/Footer pair to choose to confirm or reject the address.
-
-An extra button under the raw address enables to open a modal page to see the address as a QR code.
-
-The @ref nbgl_useCaseAddressConfirmation() function enables to create such a page, with the following parameters:
-
-- the address to confirm (NULL terminated string)
-- a callback called when button or footer is touched (if true, confirm, if false reject)
+@subsection use_case_addr_review Address Review Use Case
-Here is the code to display something similar to example picture:
+\image{inline} html UseCase-AddressReview.png "caption" height=500
-@code
-// called when either confirm button or reject token is called
-static void displayAddressCallback(bool confirm) {
- if (confirm) {
- nbgl_useCaseStatus("Address\nVerified",true,app_fullEthereum);
- }
- else {
- nbgl_useCaseStatus("Address rejected",false,app_fullEthereum);
- }
-}
-
-// called when tapping on review start page to actually display address
-static void displayAddr(void) {
- nbgl_useCaseAddressConfirmation("bc1pkdcufjh6dxjaaa05hudvxqg5fhspfmwmp8g92gq8cv4gwwnmgrfqfd4jlg", &displayAddressCallback);
-}
-
-void app_ethereumVerifyAddress(void) {
- nbgl_useCaseReviewStart(myAppIcon,"Verify MyCoin\naddress",NULL,"Cancel",
- displayAddr, appMain);
-}
-@endcode
-
-@subsection use_case_addr_confirm_ext Extended Address Confirmation Use Case
-
-\image{inline} html UseCase-AddressConfirmationExt.png "caption" height=500
-
-When an address needs to be confirmed, it can be displayed in a Address Confirmation Use Case, at first as simple page with
-the raw address (as text). An extra button under the raw address enables to open a modal page to see the address as a QR code.
+When an address needs to be confirmed, it can be displayed in a Address Review Use Case.
+After a title page, a second page is displayed with the raw address (as text). An extra button under the raw address enables to open a modal page to see the address as a QR code.
Moreover, if extra information need to be displayed, for example a derivation path, it is provided in a second page, also containing
a black button/Footer pair to choose to confirm or reject the address.
-The @ref nbgl_useCaseAddressConfirmationExt() function enables to create such a set of pages, with the following parameters:
+The @ref nbgl_useCaseAddressReview() function enables to create such a set of pages, with the following parameters:
- the address to confirm (NULL terminated string)
- a callback called when button or footer is touched (if true, confirm, if false reject)
@@ -522,14 +502,13 @@ static void displayAddressCallback(bool confirm) {
}
}
-// called when tapping on review start page to actually display address
-static void displayAddr(void) {
- nbgl_useCaseAddressConfirmationExt("bc1pkdcufjh6dxjaaa05hudvxqg5fhspfmwmp8g92gq8cv4gwwnmgrfqfd4jlg", &displayAddressCallback, &pairList);
-}
-
void app_ethereumVerifyAddress(void) {
- nbgl_useCaseReviewStart(myAppIcon,"Verify MyCoin\naddress",NULL,"Cancel",
- displayAddr, appMain);
+ nbgl_useCaseAddressReview("bc1pkdcufjh6dxjaaa05hudvxqg5fhspfmwmp8g92gq8cv4gwwnmgrfqfd4jlg",
+ &pairList
+ myAppIcon,
+ "Verify MyCoin\naddress",
+ NULL,"Cancel",
+ appMain);
}
@endcode
diff --git a/lib_nbgl/doc/resources/UseCase-AddressConfirmation.png b/lib_nbgl/doc/resources/UseCase-AddressConfirmation.png
deleted file mode 100755
index 3f4cc7e12..000000000
Binary files a/lib_nbgl/doc/resources/UseCase-AddressConfirmation.png and /dev/null differ
diff --git a/lib_nbgl/doc/resources/UseCase-AddressConfirmationExt.png b/lib_nbgl/doc/resources/UseCase-AddressConfirmationExt.png
deleted file mode 100755
index 38f0f113b..000000000
Binary files a/lib_nbgl/doc/resources/UseCase-AddressConfirmationExt.png and /dev/null differ
diff --git a/lib_nbgl/doc/resources/UseCase-AddressReview.png b/lib_nbgl/doc/resources/UseCase-AddressReview.png
new file mode 100755
index 000000000..1365fa718
Binary files /dev/null and b/lib_nbgl/doc/resources/UseCase-AddressReview.png differ
diff --git a/lib_nbgl/doc/resources/UseCase-Home.png b/lib_nbgl/doc/resources/UseCase-Home.png
deleted file mode 100755
index e90915123..000000000
Binary files a/lib_nbgl/doc/resources/UseCase-Home.png and /dev/null differ
diff --git a/lib_nbgl/doc/resources/UseCase-HomeAction.png b/lib_nbgl/doc/resources/UseCase-HomeAction.png
new file mode 100755
index 000000000..e82428611
Binary files /dev/null and b/lib_nbgl/doc/resources/UseCase-HomeAction.png differ
diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h
index c74199d5c..0fd7dca6d 100644
--- a/lib_nbgl/include/nbgl_layout.h
+++ b/lib_nbgl/include/nbgl_layout.h
@@ -277,21 +277,24 @@ typedef struct {
*
*/
typedef enum {
- ROUNDED_AND_FOOTER_STYLE
- = 0, ///< A rounded black background full width button on top of a footer
- BOTH_ROUNDED_STYLE ///< A rounded black background full width button on top of a rounded white
- ///< background full width button
+ ROUNDED_AND_FOOTER_STYLE = 0, ///< A black background button on top of a footer
+ STRONG_ACTION_AND_FOOTER_STYLE, ///< A black button on top of a footer, with a separation line
+ SOFT_ACTION_AND_FOOTER_STYLE ///< A white button on top of a footer, with a separation line
} nbgl_layoutChoiceButtonsStyle_t;
+// for backward compatibility
+#define BOTH_ROUNDED_STYLE SOFT_ACTION_AND_FOOTER_STYLE
+
/**
* @brief This structure contains info to build a pair of buttons, one on top of the other.
*
* @note the pair of button is automatically put on bottom of screen, in the footer
*/
typedef struct {
- const char *topText; ///< up-button text (index 0)
- const char *bottomText; ///< bottom-button text (index 1)
- uint8_t token; ///< the token that will be used as argument of the callback
+ const char *topText; ///< up-button text (index 0)
+ const char *bottomText; ///< bottom-button text (index 1)
+ const nbgl_icon_details_t *topIcon; ///< icon of top button
+ uint8_t token; ///< the token that will be used as argument of the callback
nbgl_layoutChoiceButtonsStyle_t style; ///< the style of the pair
#ifdef HAVE_PIEZO_SOUND
tune_index_e tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played
@@ -501,7 +504,7 @@ typedef struct {
} textAndNav; ///< if type is @ref FOOTER_TEXT_AND_NAV
nbgl_layoutNavigationBar_t navigation; ///< if type is @ref FOOTER_NAV
nbgl_layoutButton_t button; ///< if type is @ref FOOTER_SIMPLE_BUTTON
- nbgl_layoutChoiceButtons_t choiceButtons; ///< if type is @ref FOOTER_SIMPLE_BUTTON
+ nbgl_layoutChoiceButtons_t choiceButtons; ///< if type is @ref FOOTER_CHOICE_BUTTONS
};
} nbgl_layoutFooter_t;
diff --git a/lib_nbgl/include/nbgl_page.h b/lib_nbgl/include/nbgl_page.h
index 5edfbff9e..26f97c8a9 100644
--- a/lib_nbgl/include/nbgl_page.h
+++ b/lib_nbgl/include/nbgl_page.h
@@ -197,7 +197,9 @@ typedef struct nbgl_pageInfoDescription_s {
uint8_t tapActionToken; ///< the token that will be used as argument of the onActionCallback,
///< when tapped or swiped
const char
- *actionButtonText; ///< if not NULL a black "action" button is set under the centered info
+ *actionButtonText; ///< if not NULL an "action" button is set under the centered info
+ const nbgl_icon_details_t *actionButtonIcon; ///< potential icon of "action" button
+ nbgl_layoutButtonStyle_t actionButtonStyle; ///< style of "action" button
tune_index_e
tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played when button/footer is pressed
} nbgl_pageInfoDescription_t;
diff --git a/lib_nbgl/include/nbgl_use_case.h b/lib_nbgl/include/nbgl_use_case.h
index f926f3378..653fcaa12 100644
--- a/lib_nbgl/include/nbgl_use_case.h
+++ b/lib_nbgl/include/nbgl_use_case.h
@@ -153,10 +153,24 @@ typedef struct {
uint8_t nbContents; ///< number of contents
} nbgl_genericContents_t;
+/**
+ * @brief The different types of action button in Home Screen
+ *
+ */
+typedef enum {
+ STRONG_HOME_ACTION = 0, ///< Black button, implicating the main action of the App
+ SOFT_HOME_ACTION ///< White button, more for extended features
+} nbgl_homeActionStyle_t;
+
+/**
+ * @brief Structure describing the action button in Home Screen
+ *
+ */
typedef struct {
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_callback_t callback; ///< function to call when action button is touched in Home page
+ nbgl_homeActionStyle_t style; ///< style of action button
} nbgl_homeAction_t;
/**
diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c
index a300095e9..c0f9caeeb 100644
--- a/lib_nbgl/src/nbgl_layout.c
+++ b/lib_nbgl/src/nbgl_layout.c
@@ -40,19 +40,23 @@
#define TAG_VALUE_ICON_WIDTH 32
#ifdef TARGET_STAX
-#define RADIO_CHOICE_HEIGHT 96
-#define FOOTER_HEIGHT 80
-#define BAR_INTERVALE 12
-#define BACK_KEY_WIDTH 88
-#define FOOTER_BUTTON_HEIGHT 128
-#define UP_FOOTER_BUTTON_HEIGHT 120
+#define RADIO_CHOICE_HEIGHT 96
+#define FOOTER_HEIGHT 80
+#define BAR_INTERVALE 12
+#define BACK_KEY_WIDTH 88
+#define FOOTER_BUTTON_HEIGHT 128
+#define UP_FOOTER_BUTTON_HEIGHT 120
+#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
+#define ACTION_AND_FOOTER_FOOTER_HEIGHT 216
#else // TARGET_STAX
-#define RADIO_CHOICE_HEIGHT 92
-#define FOOTER_HEIGHT 80
-#define BAR_INTERVALE 16
-#define BACK_KEY_WIDTH 104
-#define FOOTER_BUTTON_HEIGHT 136
-#define UP_FOOTER_BUTTON_HEIGHT 136
+#define RADIO_CHOICE_HEIGHT 92
+#define FOOTER_HEIGHT 80
+#define BAR_INTERVALE 16
+#define BACK_KEY_WIDTH 104
+#define FOOTER_BUTTON_HEIGHT 136
+#define UP_FOOTER_BUTTON_HEIGHT 136
+#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
+#define ACTION_AND_FOOTER_FOOTER_HEIGHT 232
#endif // TARGET_STAX
// refresh period of the spinner, in ms
@@ -1765,6 +1769,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu
footerDesc.choiceButtons.bottomText = info->bottomText;
footerDesc.choiceButtons.token = info->token;
footerDesc.choiceButtons.topText = info->topText;
+ footerDesc.choiceButtons.topIcon = info->topIcon;
footerDesc.choiceButtons.style = info->style;
footerDesc.choiceButtons.tuneId = info->tuneId;
return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
@@ -2749,7 +2754,7 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
return -1;
}
- // create bottomButton (in white) at first
+ // create bottom button (footer) at first
button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
obj = layoutAddCallbackObj(layoutInt,
(nbgl_obj_t *) button,
@@ -2761,31 +2766,25 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
// associate with with index 1
obj->index = 1;
// put at the bottom of the container
- button->obj.alignment = BOTTOM_MIDDLE;
- if (footerDesc->choiceButtons.style == ROUNDED_AND_FOOTER_STYLE) {
- button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
- button->borderColor = WHITE;
- }
- else if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
- button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
- button->borderColor = WHITE; // not a real round button on Flex
- }
- button->innerColor = WHITE;
- button->foregroundColor = BLACK;
- button->obj.area.width = AVAILABLE_WIDTH;
- button->obj.area.height = BUTTON_DIAMETER;
- button->radius = BUTTON_RADIUS;
- button->text = PIC(footerDesc->choiceButtons.bottomText);
- button->fontId = SMALL_BOLD_FONT;
- button->obj.touchMask = (1 << TOUCHED);
- button->obj.touchId = CHOICE_2_ID;
+ button->obj.alignment = BOTTOM_MIDDLE;
+ button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
+ button->borderColor = WHITE;
+ button->innerColor = WHITE;
+ button->foregroundColor = BLACK;
+ button->obj.area.width = AVAILABLE_WIDTH;
+ button->obj.area.height = BUTTON_DIAMETER;
+ button->radius = BUTTON_RADIUS;
+ button->text = PIC(footerDesc->choiceButtons.bottomText);
+ button->fontId = SMALL_BOLD_FONT;
+ button->obj.touchMask = (1 << TOUCHED);
+ button->obj.touchId = CHOICE_2_ID;
// add to bottom container
layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
= (nbgl_obj_t *) button;
layoutInt->footerContainer->nbChildren++;
// add line if needed
- if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
+ if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
line = createHorizontalLine(layoutInt->layer);
line->obj.alignment = TOP_MIDDLE;
line->obj.alignmentMarginY = 4;
@@ -2795,7 +2794,7 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
layoutInt->footerContainer->nbChildren++;
}
- // then black button, on top of it
+ // then top button, on top of it
button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
obj = layoutAddCallbackObj(layoutInt,
(nbgl_obj_t *) button,
@@ -2807,8 +2806,8 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
// associate with with index 0
obj->index = 0;
button->obj.alignment = TOP_MIDDLE;
- button->obj.alignmentMarginY = 24; // 12 pixels from bottom button
- if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
+ button->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN; // 24 pixels from top of container
+ if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
button->innerColor = WHITE;
button->borderColor = LIGHT_GRAY;
button->foregroundColor = BLACK;
@@ -2822,6 +2821,9 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
button->obj.area.height = BUTTON_DIAMETER;
button->radius = BUTTON_RADIUS;
button->text = PIC(footerDesc->choiceButtons.topText);
+ button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
+ ? PIC(footerDesc->choiceButtons.topIcon)
+ : NULL;
button->fontId = SMALL_BOLD_FONT;
button->obj.touchMask = (1 << TOUCHED);
button->obj.touchId = CHOICE_1_ID;
@@ -2830,21 +2832,12 @@ int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_
= (nbgl_obj_t *) button;
layoutInt->footerContainer->nbChildren++;
-#ifdef TARGET_STAX
- if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
- layoutInt->footerContainer->obj.area.height = 232;
+ if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
+ layoutInt->footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
}
else {
- layoutInt->footerContainer->obj.area.height = 192;
+ layoutInt->footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
}
-#else // TARGET_STAX
- if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
- layoutInt->footerContainer->obj.area.height = 232;
- }
- else {
- layoutInt->footerContainer->obj.area.height = 208;
- }
-#endif // TARGET_STAX
break;
}
diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c
index cf99d9b4c..25f0a2a05 100644
--- a/lib_nbgl/src/nbgl_page.c
+++ b/lib_nbgl/src/nbgl_page.c
@@ -362,9 +362,9 @@ nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionC
// if action button but not QUIT_APP_TEXT bottom button, use a small black button
if ((info->actionButtonText != NULL) && (info->bottomButtonStyle != QUIT_APP_TEXT)) {
nbgl_layoutButton_t buttonInfo = {.fittingContent = true,
- .icon = NULL,
+ .icon = info->actionButtonIcon,
.onBottom = false,
- .style = BLACK_BACKGROUND,
+ .style = info->actionButtonStyle,
.text = info->actionButtonText,
.token = info->bottomButtonsToken,
.tuneId = info->tuneId};
@@ -397,7 +397,11 @@ nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionC
.bottomText = "Quit app",
.token = info->bottomButtonsToken,
.style = BOTH_ROUNDED_STYLE,
- .tuneId = info->tuneId};
+ .tuneId = info->tuneId,
+ .topIcon = info->actionButtonIcon};
+ buttonsInfo.style = (info->actionButtonStyle == BLACK_BACKGROUND)
+ ? STRONG_ACTION_AND_FOOTER_STYLE
+ : SOFT_ACTION_AND_FOOTER_STYLE;
nbgl_layoutAddChoiceButtons(layout, &buttonsInfo);
}
else {
diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c
index a0b908b2e..508cc18c7 100644
--- a/lib_nbgl/src/nbgl_use_case.c
+++ b/lib_nbgl/src/nbgl_use_case.c
@@ -152,8 +152,7 @@ typedef struct {
const char *tagline;
const nbgl_genericContents_t *settingContents;
const nbgl_contentInfoList_t *infosList;
- const char *actionText;
- nbgl_callback_t actionCallback;
+ nbgl_homeAction_t homeAction;
nbgl_callback_t quitCallback;
} nbgl_homeAndSettingsContext_t;
@@ -287,6 +286,13 @@ static void useCaseReviewStreamingStart(nbgl_operationType_t operationType
const char *reviewSubTitle,
nbgl_choiceCallback_t choiceCallback,
bool playNotifSound);
+static void useCaseHomeExt(const char *appName,
+ const nbgl_icon_details_t *appIcon,
+ const char *tagline,
+ bool withSettings,
+ nbgl_homeAction_t *homeAction,
+ nbgl_callback_t topRightCallback,
+ nbgl_callback_t quitCallback);
static void reset_callbacks(void)
{
@@ -1603,14 +1609,13 @@ static void bundleNavStartHome(void)
{
nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
- nbgl_useCaseHomeExt(context->appName,
- context->appIcon,
- context->tagline,
- context->settingContents != NULL ? true : false,
- context->actionText,
- context->actionCallback,
- bundleNavStartSettings,
- context->quitCallback);
+ useCaseHomeExt(context->appName,
+ context->appIcon,
+ context->tagline,
+ context->settingContents != NULL ? true : false,
+ &context->homeAction,
+ bundleNavStartSettings,
+ context->quitCallback);
}
static void bundleNavStartSettingsAtPage(uint8_t initSettingPage)
@@ -1856,6 +1861,97 @@ static void useCaseReviewStreamingStart(nbgl_operationType_t operationType
displayGenericContextPage(0, true);
}
+/**
+ * @brief draws the extended version of home page of an app (page on which we land when launching it
+ * from dashboard)
+ * @note it enables to use an action button (black on Stax, white on Flex)
+ *
+ * @param appName app name
+ * @param appIcon app icon
+ * @param tagline text under app name (if NULL, it will be "This app enables signing transactions on
+ * the network.")
+ * @param withSettings if true, use a "settings" (wheel) icon in bottom button, otherwise a "info"
+ * (i)
+ * @param homeAction if not NULL, structure used for an action button (on top of "Quit
+ * App" button/footer)
+ * @param topRightCallback callback called when top-right button is touched
+ * @param quitCallback callback called when quit button is touched
+ */
+static void useCaseHomeExt(const char *appName,
+ const nbgl_icon_details_t *appIcon,
+ const char *tagline,
+ bool withSettings,
+ nbgl_homeAction_t *homeAction,
+ nbgl_callback_t topRightCallback,
+ nbgl_callback_t quitCallback)
+{
+ reset_callbacks();
+
+ nbgl_pageInfoDescription_t info = {.centeredInfo.icon = appIcon,
+ .centeredInfo.text1 = appName,
+ .centeredInfo.text3 = NULL,
+ .centeredInfo.style = LARGE_CASE_INFO,
+ .centeredInfo.offsetY = 0,
+ .footerText = NULL,
+ .bottomButtonStyle = QUIT_APP_TEXT,
+ .tapActionText = NULL,
+ .topRightStyle = withSettings ? SETTINGS_ICON : INFO_ICON,
+ .topRightToken = CONTINUE_TOKEN,
+ .tuneId = TUNE_TAP_CASUAL};
+ if ((homeAction->text != NULL) || (homeAction->icon != NULL)) {
+ // trick to use ACTION_BUTTON_TOKEN for action and quit, with index used to distinguish
+ info.bottomButtonsToken = ACTION_BUTTON_TOKEN;
+ onAction = homeAction->callback;
+ info.actionButtonText = homeAction->text;
+ info.actionButtonIcon = homeAction->icon;
+ info.actionButtonStyle
+ = (homeAction->style == STRONG_HOME_ACTION) ? BLACK_BACKGROUND : WHITE_BACKGROUND;
+ }
+ else {
+ info.bottomButtonsToken = QUIT_TOKEN;
+ onAction = NULL;
+ info.actionButtonText = NULL;
+ info.actionButtonIcon = NULL;
+ }
+ if (tagline == NULL) {
+ if (strlen(appName) > MAX_APP_NAME_FOR_SDK_TAGLINE) {
+ snprintf(appDescription,
+ APP_DESCRIPTION_MAX_LEN,
+ "This app enables signing\ntransactions on its network.");
+ }
+ else {
+ snprintf(appDescription,
+ APP_DESCRIPTION_MAX_LEN,
+ "%s %s\n%s",
+ TAGLINE_PART1,
+ appName,
+ TAGLINE_PART2);
+ }
+
+ // If there is more than 3 lines, it means the appName was split, so we put it on the next
+ // line
+ if (nbgl_getTextNbLinesInWidth(SMALL_REGULAR_FONT, appDescription, AVAILABLE_WIDTH, false)
+ > 3) {
+ snprintf(appDescription,
+ APP_DESCRIPTION_MAX_LEN,
+ "%s\n%s %s",
+ TAGLINE_PART1,
+ appName,
+ TAGLINE_PART2);
+ }
+ info.centeredInfo.text2 = appDescription;
+ }
+ else {
+ info.centeredInfo.text2 = tagline;
+ }
+
+ onContinue = topRightCallback;
+ onQuit = quitCallback;
+
+ pageContext = nbgl_pageDrawInfo(&pageCallback, NULL, &info);
+ nbgl_refreshSpecial(FULL_COLOR_CLEAN_REFRESH);
+}
+
/**********************
* GLOBAL FUNCTIONS
**********************/
@@ -2215,68 +2311,13 @@ void nbgl_useCaseHomeExt(const char *appName,
nbgl_callback_t topRightCallback,
nbgl_callback_t quitCallback)
{
- reset_callbacks();
+ nbgl_homeAction_t homeAction = {.callback = actionCallback,
+ .icon = NULL,
+ .style = STRONG_HOME_ACTION,
+ .text = actionButtonText};
- nbgl_pageInfoDescription_t info = {.centeredInfo.icon = appIcon,
- .centeredInfo.text1 = appName,
- .centeredInfo.text3 = NULL,
- .centeredInfo.style = LARGE_CASE_INFO,
- .centeredInfo.offsetY = 0,
- .footerText = NULL,
- .bottomButtonStyle = QUIT_APP_TEXT,
- .tapActionText = NULL,
- .topRightStyle = withSettings ? SETTINGS_ICON : INFO_ICON,
- .topRightToken = CONTINUE_TOKEN,
- .actionButtonText = actionButtonText,
- .tuneId = TUNE_TAP_CASUAL};
- if (actionButtonText != NULL) {
- // trick to use ACTION_BUTTON_TOKEN for action and quit, with index used to distinguish
- info.bottomButtonsToken = ACTION_BUTTON_TOKEN;
- onAction = actionCallback;
- }
- else {
- info.bottomButtonsToken = QUIT_TOKEN;
- onAction = actionCallback;
- }
- if (tagline == NULL) {
- if (strlen(appName) > MAX_APP_NAME_FOR_SDK_TAGLINE) {
- snprintf(appDescription,
- APP_DESCRIPTION_MAX_LEN,
- "This app enables signing\ntransactions on its network.");
- }
- else {
- snprintf(appDescription,
- APP_DESCRIPTION_MAX_LEN,
- "%s %s\n%s",
- TAGLINE_PART1,
- appName,
- TAGLINE_PART2);
- }
-
- // If there is more than 3 lines, it means the appName was split, so we put it on the next
- // line
- if (nbgl_getTextNbLinesInWidth(SMALL_REGULAR_FONT, appDescription, AVAILABLE_WIDTH, false)
- > 3) {
- snprintf(appDescription,
- APP_DESCRIPTION_MAX_LEN,
- "%s\n%s %s",
- TAGLINE_PART1,
- appName,
- TAGLINE_PART2);
- }
- info.centeredInfo.text2 = appDescription;
- }
- else {
- info.centeredInfo.text2 = tagline;
- }
-
- onContinue = topRightCallback;
- onQuit = quitCallback;
- if (actionButtonText != NULL) {
- info.centeredInfo.offsetY -= 40;
- }
- pageContext = nbgl_pageDrawInfo(&pageCallback, NULL, &info);
- nbgl_refreshSpecial(FULL_COLOR_CLEAN_REFRESH);
+ useCaseHomeExt(
+ appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
}
/**
@@ -2482,12 +2523,10 @@ void nbgl_useCaseHomeAndSettings(
context->settingContents = settingContents;
context->infosList = infosList;
if (action != NULL) {
- context->actionText = action->text;
- context->actionCallback = action->callback;
+ memcpy(&context->homeAction, action, sizeof(nbgl_homeAction_t));
}
else {
- context->actionText = NULL;
- context->actionCallback = NULL;
+ memset(&context->homeAction, 0, sizeof(nbgl_homeAction_t));
}
context->quitCallback = quitCallback;