Skip to content

Commit f4f8495

Browse files
committed
src/fw/shell/normal: new combo back + up quick launch
Signed-off-by: Federico Bechini <federico.bechini@gmail.com>
1 parent e5e6aad commit f4f8495

7 files changed

Lines changed: 119 additions & 3 deletions

File tree

src/fw/applib/ui/click.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ void click_manager_clear(ClickManager* click_manager) {
365365
}
366366
}
367367

368+
void click_recognizer_reset(ClickRecognizer *recognizer) {
369+
prv_click_reset(recognizer);
370+
}
371+
368372
void click_manager_reset(ClickManager* click_manager) {
369373
for (unsigned int button_id = 0; button_id < NUM_BUTTONS; button_id++) {
370374
prv_click_reset(&click_manager->recognizers[button_id]);

src/fw/applib/ui/click_internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ void click_recognizer_handle_button_up(ClickRecognizer *recognizer);
6363
//! Tell the particular recognizer that the associated button has been pressed.
6464
void click_recognizer_handle_button_down(ClickRecognizer *recognizer);
6565

66+
//! Reset the state of a single recognizer, including timers.
67+
void click_recognizer_reset(ClickRecognizer *recognizer);
68+
6669
//! Initialize a click manager for use. This only needs to be called once to initialize the structure, and then the
6770
//! same struct can be reconfigured multiple times by using click_manager_clear.
6871
void click_manager_init(ClickManager* click_manager);

src/fw/services/normal/blob_db/settings_blob_db.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static const char *s_syncable_settings[] = {
7878
"qlSetupOpened",
7979
"qlSingleClickUp",
8080
"qlSingleClickDown",
81+
"qlComboBackUp",
8182

8283
// UI theming
8384
"settingsMenuHighlightColor",

src/fw/shell/normal/prefs.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ static QuickLaunchPreference s_quick_launch_back = {
143143

144144
#define PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_UP "qlSingleClickUp"
145145
#define PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_DOWN "qlSingleClickDown"
146+
#define PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP "qlComboBackUp"
146147

147148
static QuickLaunchPreference s_quick_launch_single_click_up = {
148149
.enabled = true,
@@ -154,6 +155,11 @@ static QuickLaunchPreference s_quick_launch_single_click_down = {
154155
.uuid = TIMELINE_UUID_INIT,
155156
};
156157

158+
static QuickLaunchPreference s_quick_launch_combo_back_up = {
159+
.enabled = false,
160+
.uuid = UUID_INVALID_INIT,
161+
};
162+
157163
#define PREF_KEY_QUICK_LAUNCH_SETUP_OPENED "qlSetupOpened"
158164
static uint8_t s_quick_launch_setup_opened = 0;
159165

@@ -427,6 +433,12 @@ static bool prv_set_s_quick_launch_single_click_down(QuickLaunchPreference *pref
427433
return true;
428434
}
429435

436+
static bool prv_set_s_quick_launch_combo_back_up(QuickLaunchPreference *pref) {
437+
prv_normalize_quick_launch_pref(pref);
438+
s_quick_launch_combo_back_up = *pref;
439+
return true;
440+
}
441+
430442
static bool prv_set_s_quick_launch_setup_opened(uint8_t *version) {
431443
s_quick_launch_setup_opened = *version;
432444
return true;
@@ -1318,6 +1330,28 @@ void quick_launch_single_click_set_enabled(ButtonId button, bool enabled) {
13181330
prv_pref_set(key, &pref, sizeof(pref));
13191331
}
13201332

1333+
bool quick_launch_combo_back_up_is_enabled(void) {
1334+
return s_quick_launch_combo_back_up.enabled;
1335+
}
1336+
1337+
AppInstallId quick_launch_combo_back_up_get_app(void) {
1338+
return app_install_get_id_for_uuid(&s_quick_launch_combo_back_up.uuid);
1339+
}
1340+
1341+
void quick_launch_combo_back_up_set_app(AppInstallId app_id) {
1342+
QuickLaunchPreference pref = (QuickLaunchPreference) {
1343+
.enabled = true,
1344+
};
1345+
app_install_get_uuid_for_install_id(app_id, &pref.uuid);
1346+
prv_pref_set(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, &pref, sizeof(pref));
1347+
}
1348+
1349+
void quick_launch_combo_back_up_set_enabled(bool enabled) {
1350+
QuickLaunchPreference pref = s_quick_launch_combo_back_up;
1351+
pref.enabled = enabled;
1352+
prv_pref_set(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, &pref, sizeof(pref));
1353+
}
1354+
13211355
void watchface_set_default_install_id(AppInstallId app_id) {
13221356
Uuid uuid;
13231357
app_install_get_uuid_for_install_id(app_id, &uuid);

src/fw/shell/normal/prefs_values.h.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_BACK, s_quick_launch_back)
2525
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_UP, s_quick_launch_single_click_up)
2626
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SINGLE_CLICK_DOWN, s_quick_launch_single_click_down)
27+
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_COMBO_BACK_UP, s_quick_launch_combo_back_up)
2728
PREFS_MACRO(PREF_KEY_QUICK_LAUNCH_SETUP_OPENED, s_quick_launch_setup_opened)
2829
PREFS_MACRO(PREF_KEY_DEFAULT_WATCHFACE, s_default_watchface)
2930
PREFS_MACRO(PREF_KEY_WELCOME_VERSION, s_welcome_version)

src/fw/shell/normal/quick_launch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ bool quick_launch_single_click_is_enabled(ButtonId button);
1818
AppInstallId quick_launch_single_click_get_app(ButtonId button);
1919
void quick_launch_single_click_set_app(ButtonId button, AppInstallId app_id);
2020
void quick_launch_single_click_set_enabled(ButtonId button, bool enabled);
21+
22+
bool quick_launch_combo_back_up_is_enabled(void);
23+
AppInstallId quick_launch_combo_back_up_get_app(void);
24+
void quick_launch_combo_back_up_set_app(AppInstallId app_id);
25+
void quick_launch_combo_back_up_set_enabled(bool enabled);

src/fw/shell/normal/watchface.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@
1818
#include "process_management/pebble_process_md.h"
1919
#include "services/common/analytics/analytics.h"
2020
#include "services/common/compositor/compositor_transitions.h"
21+
#include "applib/app_timer.h"
22+
#include "applib/ui/click_internal.h"
2123
#include "services/normal/notifications/do_not_disturb.h"
2224
#include "system/logging.h"
2325
#include "system/passert.h"
2426

2527
#define QUICK_LAUNCH_HOLD_MS (400)
28+
#define BIT_SET (1)
29+
#define BIT_CLEAR (0)
30+
#define COMBO_BACK_UP_BUTTONS ((BIT_SET << BUTTON_ID_BACK) | (BIT_SET << BUTTON_ID_UP))
2631

2732
static ClickManager s_click_manager;
33+
static uint8_t s_buttons_pressed = BIT_CLEAR;
34+
static AppTimer *s_combo_back_up_timer = NULL;
2835

2936
static bool prv_should_ignore_button_click(void) {
3037
if (app_manager_get_task_context()->closing_state != ProcessRunState_Running) {
@@ -44,28 +51,82 @@ static void prv_launch_app_via_button(AppLaunchEventConfig *config,
4451
app_manager_put_launch_app_event(config);
4552
}
4653

54+
static void prv_combo_back_up_timer_callback(void *data) {
55+
s_combo_back_up_timer = NULL;
56+
// Double-check that both buttons are still pressed before executing combo
57+
if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
58+
if (quick_launch_combo_back_up_is_enabled()) {
59+
AppInstallId app_id = quick_launch_combo_back_up_get_app();
60+
if (app_id != INSTALL_ID_INVALID) {
61+
// Reset all button states before launching app to prevent state corruption
62+
s_buttons_pressed = BIT_CLEAR; // Reset our own tracking
63+
app_manager_put_launch_app_event(&(AppLaunchEventConfig) {
64+
.id = app_id,
65+
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
66+
.common.button = BUTTON_ID_BACK,
67+
});
68+
return;
69+
}
70+
}
71+
}
72+
}
73+
74+
static void prv_check_combo_back_up(void) {
75+
bool back_pressed = (s_buttons_pressed & (BIT_SET << BUTTON_ID_BACK)) != BIT_CLEAR;
76+
bool up_pressed = (s_buttons_pressed & (BIT_SET << BUTTON_ID_UP)) != BIT_CLEAR;
77+
bool both_pressed = back_pressed && up_pressed;
78+
79+
if (both_pressed) {
80+
if (s_combo_back_up_timer == NULL) {
81+
// Cancel individual button timers to prevent them from firing
82+
// This ensures only the combo executes, not individual hold handlers
83+
click_recognizer_reset(&s_click_manager.recognizers[BUTTON_ID_BACK]);
84+
click_recognizer_reset(&s_click_manager.recognizers[BUTTON_ID_UP]);
85+
s_combo_back_up_timer = app_timer_register(QUICK_LAUNCH_HOLD_MS, prv_combo_back_up_timer_callback, NULL);
86+
}
87+
} else {
88+
if (s_combo_back_up_timer != NULL) {
89+
app_timer_cancel(s_combo_back_up_timer);
90+
s_combo_back_up_timer = NULL;
91+
}
92+
}
93+
}
94+
4795
static void prv_quick_launch_handler(ClickRecognizerRef recognizer, void *data) {
4896
ButtonId button = click_recognizer_get_button_id(recognizer);
97+
98+
if (s_combo_back_up_timer != NULL ||
99+
(s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
100+
return;
101+
}
102+
49103
if (!quick_launch_is_enabled(button)) {
50104
return;
51105
}
52106
AppInstallId app_id = quick_launch_get_app(button);
53107
if (app_id == INSTALL_ID_INVALID) {
54108
app_id = app_install_get_id_for_uuid(&quick_launch_setup_get_app_info()->uuid);
55109
}
110+
s_buttons_pressed = BIT_CLEAR; // Reset our own tracking
56111
prv_launch_app_via_button(&(AppLaunchEventConfig) {
57112
.id = app_id,
58113
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
59114
}, recognizer);
60115
}
61116

62117
static void prv_launch_up_down(ClickRecognizerRef recognizer, void *data) {
63-
if (!quick_launch_single_click_is_enabled(click_recognizer_get_button_id(recognizer))) return;
118+
ButtonId button = click_recognizer_get_button_id(recognizer);
119+
120+
if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
121+
return;
122+
}
123+
124+
if (!quick_launch_single_click_is_enabled(button)) return;
64125
//check if quick launch app is not timeline
65-
if (quick_launch_single_click_get_app(click_recognizer_get_button_id(recognizer)) != APP_ID_TIMELINE) {
126+
if (quick_launch_single_click_get_app(button) != APP_ID_TIMELINE) {
66127
//launch other quick launch apps
67128
prv_launch_app_via_button(&(AppLaunchEventConfig) {
68-
.id = quick_launch_single_click_get_app(click_recognizer_get_button_id(recognizer)),
129+
.id = quick_launch_single_click_get_app(button),
69130
.common.reason = APP_LAUNCH_QUICK_LAUNCH,
70131
}, recognizer);
71132
return;
@@ -120,6 +181,9 @@ static void prv_launch_launcher_app(ClickRecognizerRef recognizer, void *data) {
120181
}
121182

122183
static void prv_dismiss_timeline_peek(ClickRecognizerRef recognizer, void *data) {
184+
if ((s_buttons_pressed & COMBO_BACK_UP_BUTTONS) == COMBO_BACK_UP_BUTTONS) {
185+
return;
186+
}
123187
timeline_peek_dismiss();
124188
}
125189

@@ -141,9 +205,13 @@ void watchface_handle_button_event(PebbleEvent *e) {
141205
}
142206
switch (e->type) {
143207
case PEBBLE_BUTTON_DOWN_EVENT:
208+
s_buttons_pressed |= (BIT_SET << e->button.button_id);
144209
click_recognizer_handle_button_down(&s_click_manager.recognizers[e->button.button_id]);
210+
prv_check_combo_back_up();
145211
break;
146212
case PEBBLE_BUTTON_UP_EVENT:
213+
s_buttons_pressed &= ~(BIT_SET << e->button.button_id);
214+
prv_check_combo_back_up();
147215
click_recognizer_handle_button_up(&s_click_manager.recognizers[e->button.button_id]);
148216
break;
149217
default:

0 commit comments

Comments
 (0)