Skip to content

Commit 58f47cc

Browse files
josiahcbloomerclaude
authored andcommitted
fw/quick_launch: split picker into "actions" and "apps"
Toggle actions were mixed with app launches in a single list. Split the list into two sub-menus for UX clarity. Signed-off-by: Josiah Bloomer <josiah@bloomer.cc> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 64ab2b9 commit 58f47cc

3 files changed

Lines changed: 114 additions & 18 deletions

File tree

src/fw/apps/system/settings/quick_launch.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
/* SPDX-License-Identifier: Apache-2.0 */
33

44
//! This file displays the main Quick Launch menu that is found in our settings menu
5-
//! It allows the feature to be enabled or for an app to be set
6-
//! The list of apps that the user can choose from is found in settings_quick_launch_app_menu.c
5+
//! It allows the feature to be enabled or for an action or app to be set
6+
//! The list of targets that the user can choose from is found in quick_launch_app_menu.c
77
//! This file is also responsible for saving / storing the uuid of each quicklaunch app as well as
88
//! whether or not the quicklaunch app is enabled.
99

1010
#include "menu.h"
11+
#include "option_menu.h"
1112
#include "quick_launch.h"
1213
#include "quick_launch_app_menu.h"
1314
#include "quick_launch_setup_menu.h"
@@ -17,6 +18,7 @@
1718
#include "applib/app_launch_reason.h"
1819
#include "applib/ui/window_stack.h"
1920
#include "kernel/pbl_malloc.h"
21+
#include "process_management/app_install_manager.h"
2022
#include "process_management/app_menu_data_source.h"
2123
#include "resource/resource_ids.auto.h"
2224
#include "pbl/services/i18n/i18n.h"
@@ -34,9 +36,19 @@ typedef enum {
3436
ROW_HOLD_BACK,
3537
} QuickLaunchRow;
3638

39+
typedef enum {
40+
CATEGORY_ROW_ACTIONS = 0,
41+
CATEGORY_ROW_APPS,
42+
43+
CategoryRowCount,
44+
} QuickLaunchCategoryRow;
45+
3746
typedef struct QuickLaunchData {
3847
SettingsCallbacks callbacks;
3948
char app_names[NUM_ROWS][APP_NAME_SIZE_BYTES];
49+
//! The button whose binding the pushed sub-menus are editing.
50+
ButtonId button;
51+
bool is_tap;
4052
} QuickLaunchData;
4153

4254
static const char *s_row_titles[NUM_ROWS] = {
@@ -54,6 +66,13 @@ static const char *s_row_titles[NUM_ROWS] = {
5466
[ROW_HOLD_BACK] = i18n_noop("Hold Back"),
5567
};
5668

69+
static const char *s_category_row_titles[CategoryRowCount] = {
70+
/// Shown in Quick Launch Settings as the title of the list of actions.
71+
[CATEGORY_ROW_ACTIONS] = i18n_noop("Actions"),
72+
/// Shown in Quick Launch Settings as the title of the list of apps.
73+
[CATEGORY_ROW_APPS] = i18n_noop("Apps"),
74+
};
75+
5776
static void prv_get_subtitle_string(AppInstallId app_id, QuickLaunchData *data, char *buffer,
5877
uint8_t buf_len) {
5978
if (app_id == INSTALL_ID_INVALID) {
@@ -128,6 +147,35 @@ static uint16_t prv_get_initial_selection_cb(SettingsCallbacks *context) {
128147
return 0;
129148
}
130149

150+
//! The row to start on, which is the category the button is currently bound to.
151+
static QuickLaunchCategoryRow prv_get_category_row(QuickLaunchData *data) {
152+
const AppInstallId app_id = data->is_tap ? quick_launch_single_click_get_app(data->button)
153+
: quick_launch_get_app(data->button);
154+
AppInstallEntry entry;
155+
if ((app_id == INSTALL_ID_INVALID) || !app_install_get_entry_for_install_id(app_id, &entry)) {
156+
return CATEGORY_ROW_ACTIONS;
157+
}
158+
return app_install_entry_is_quick_launch_visible_only(&entry) ? CATEGORY_ROW_ACTIONS
159+
: CATEGORY_ROW_APPS;
160+
}
161+
162+
static void prv_category_menu_select(OptionMenu *option_menu, int selection, void *context) {
163+
QuickLaunchData *data = settings_option_menu_get_context(context);
164+
const QuickLaunchMenuCategory category = (selection == CATEGORY_ROW_ACTIONS)
165+
? QuickLaunchMenuCategoryActions
166+
: QuickLaunchMenuCategoryApps;
167+
quick_launch_app_menu_window_push(data->button, data->is_tap, category, &option_menu->window);
168+
}
169+
170+
static void prv_category_menu_push(QuickLaunchData *data) {
171+
const OptionMenuCallbacks callbacks = {
172+
.select = prv_category_menu_select,
173+
};
174+
settings_option_menu_push(i18n_noop("Quick Launch"), OptionMenuContentType_SingleLine,
175+
prv_get_category_row(data), &callbacks, CategoryRowCount,
176+
false /* icons_enabled */, s_category_row_titles, data);
177+
}
178+
131179
static void prv_select_click_cb(SettingsCallbacks *context, uint16_t row) {
132180
PBL_ASSERTN(row < NUM_ROWS);
133181

@@ -163,7 +211,10 @@ static void prv_select_click_cb(SettingsCallbacks *context, uint16_t row) {
163211
return;
164212
}
165213

166-
quick_launch_app_menu_window_push(button, is_tap);
214+
QuickLaunchData *data = (QuickLaunchData *)context;
215+
data->button = button;
216+
data->is_tap = is_tap;
217+
prv_category_menu_push(data);
167218
}
168219

169220
static uint16_t prv_num_rows_cb(SettingsCallbacks *context) {

src/fw/apps/system/settings/quick_launch_app_menu.c

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
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

3454
static 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) {
77103
static 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

117144
static 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,

src/fw/apps/system/settings/quick_launch_app_menu.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
#pragma once
55

66
#include "shell/normal/quick_launch.h"
7+
8+
#include "applib/ui/window.h"
9+
710
#include <stdbool.h>
811

9-
void quick_launch_app_menu_window_push(ButtonId button, bool is_tap);
12+
typedef enum QuickLaunchMenuCategory {
13+
//! Entries that are only visible in Quick Launch, e.g. the system toggles.
14+
QuickLaunchMenuCategoryActions,
15+
//! Regular launcher apps.
16+
QuickLaunchMenuCategoryApps,
17+
} QuickLaunchMenuCategory;
18+
19+
//! @param button The button whose binding is being edited.
20+
//! @param is_tap Whether the binding is for a tap rather than a hold.
21+
//! @param category Which kind of target the menu lists.
22+
//! @param parent The category menu to unwind along with this one on selection.
23+
void quick_launch_app_menu_window_push(ButtonId button, bool is_tap,
24+
QuickLaunchMenuCategory category, Window *parent);

0 commit comments

Comments
 (0)