11/* SPDX-FileCopyrightText: 2024 Google LLC */
22/* SPDX-License-Identifier: Apache-2.0 */
33
4- //! This file generates a menu that lets the user select a quicklaunch app
5- //! The menu that is generated is the same as the "main menu" but with a
6- //! title
4+ //! This file generates the menu that lets the user pick a Quick Launch target
5+ //! within one category, either an action or an app.
76
87#include "quick_launch_app_menu.h"
98#include "quick_launch_setup_menu.h"
@@ -23,12 +22,33 @@ typedef struct {
2322 AppMenuDataSource data_source ;
2423 ButtonId button ;
2524 bool is_tap ;
26- int16_t selected ;
25+ QuickLaunchMenuCategory category ;
26+ Window * parent ;
2727 OptionMenu * option_menu ;
2828} QuickLaunchAppMenuData ;
2929
30+ //! Row 0 of both categories un-assigns the button; the data source starts after it.
3031#define NUM_CUSTOM_CELLS 1
3132
33+ static const char * s_category_titles [] = {
34+ /// Title of the Quick Launch menu listing the available actions.
35+ [QuickLaunchMenuCategoryActions ] = i18n_noop ("Actions" ),
36+ /// Title of the Quick Launch menu listing the installed apps.
37+ [QuickLaunchMenuCategoryApps ] = i18n_noop ("Apps" ),
38+ };
39+
40+ //! Row 0 when nothing is bound, the matching entry when it is in this category, and no
41+ //! selection at all when the button is bound to something in the other category.
42+ static int prv_choice (AppInstallId install_id , uint16_t app_index ) {
43+ if (install_id == INSTALL_ID_INVALID ) {
44+ return 0 ;
45+ }
46+ if (app_index == MENU_INDEX_NOT_FOUND ) {
47+ return OPTION_MENU_CHOICE_NONE ;
48+ }
49+ return (int )app_index + NUM_CUSTOM_CELLS ;
50+ }
51+
3252/* Callback Functions */
3353
3454static bool prv_app_filter_callback (struct AppMenuDataSource * source , AppInstallEntry * entry ) {
@@ -40,9 +60,15 @@ static bool prv_app_filter_callback(struct AppMenuDataSource *source, AppInstall
4060 if (app_install_entry_is_watchface (entry )) {
4161 return false; // Skip watchfaces
4262 }
43- if (app_install_entry_is_hidden (entry ) &&
44- !app_install_entry_is_quick_launch_visible_only (entry )) {
45- return false; // Skip hidden apps unless they are quick launch visible
63+
64+ // Quick launch visible only entries are the actions, everything else is an app.
65+ const bool is_action = app_install_entry_is_quick_launch_visible_only (entry );
66+ if (data -> category == QuickLaunchMenuCategoryActions ) {
67+ if (!is_action ) {
68+ return false;
69+ }
70+ } else if (is_action || app_install_entry_is_hidden (entry )) {
71+ return false;
4672 }
4773
4874 // For tap buttons, filter Timeline apps based on button
@@ -77,7 +103,7 @@ static uint16_t prv_menu_get_num_rows(OptionMenu *option_menu, void *context) {
77103static void prv_menu_draw_row (OptionMenu * option_menu , GContext * ctx , const Layer * cell_layer ,
78104 const GRect * text_frame , uint32_t row , bool selected , void * context ) {
79105 QuickLaunchAppMenuData * data = context ;
80- const char * text = NULL ;
106+ const char * text ;
81107 if (row == 0 ) {
82108 /// Shown in Quick Launch Settings when no action or app is bound to the button.
83109 text = i18n_get ("Unassigned" , data );
@@ -101,7 +127,6 @@ static void prv_menu_select(OptionMenu *option_menu, int selection, void *contex
101127 quick_launch_set_app (data -> button , INSTALL_ID_INVALID );
102128 quick_launch_set_enabled (data -> button , false);
103129 }
104- app_window_stack_pop (true);
105130 } else {
106131 AppMenuNode * app_menu_node =
107132 app_menu_data_source_get_node_at_index (& data -> data_source , selection - NUM_CUSTOM_CELLS );
@@ -110,8 +135,10 @@ static void prv_menu_select(OptionMenu *option_menu, int selection, void *contex
110135 } else {
111136 quick_launch_set_app (data -> button , app_menu_node -> install_id );
112137 }
113- app_window_stack_pop (true);
114138 }
139+ // Unwind the category menu too, so that selecting returns to the Quick Launch settings.
140+ app_window_stack_remove (data -> parent , false);
141+ app_window_stack_pop (true);
115142}
116143
117144static void prv_menu_reload_data (void * context ) {
@@ -128,10 +155,13 @@ static void prv_menu_unload(OptionMenu *option_menu, void *context) {
128155 app_free (data );
129156}
130157
131- void quick_launch_app_menu_window_push (ButtonId button , bool is_tap ) {
158+ void quick_launch_app_menu_window_push (ButtonId button , bool is_tap ,
159+ QuickLaunchMenuCategory category , Window * parent ) {
132160 QuickLaunchAppMenuData * data = app_zalloc_check (sizeof (* data ));
133161 data -> button = button ;
134162 data -> is_tap = is_tap ;
163+ data -> category = category ;
164+ data -> parent = parent ;
135165
136166 OptionMenu * option_menu = option_menu_create ();
137167 data -> option_menu = option_menu ;
@@ -145,13 +175,13 @@ void quick_launch_app_menu_window_push(ButtonId button, bool is_tap) {
145175
146176 const AppInstallId install_id =
147177 is_tap ? quick_launch_single_click_get_app (button ) : quick_launch_get_app (button );
148- const int app_index =
178+ const uint16_t app_index =
149179 app_menu_data_source_get_index_of_app_with_install_id (& data -> data_source , install_id );
150180
151181 GColor highlight_bg = shell_prefs_get_theme_highlight_color ();
152182 const OptionMenuConfig config = {
153- .title = i18n_get (i18n_noop ( "Quick Launch" ) , data ),
154- .choice = (install_id == INSTALL_ID_INVALID ) ? 0 : ( app_index + NUM_CUSTOM_CELLS ),
183+ .title = i18n_get (s_category_titles [ category ] , data ),
184+ .choice = prv_choice (install_id , app_index ),
155185 .status_colors =
156186 {
157187 GColorWhite ,
0 commit comments