Skip to content

Commit 9933750

Browse files
authored
Merge pull request #30 from Nicolai-Electronics/megaschaf/message_dialog_app_inspect_delete
message_dialog: now multiple options; app_inspect menu and app deletion
2 parents 062640a + 46b2eba commit 9933750

10 files changed

Lines changed: 292 additions & 41 deletions

File tree

main/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ idf_component_register(
1717
"menu/wifi_edit.c"
1818
"menu/wifi_scan.c"
1919
"menu/apps.c"
20+
"menu/app_inspect.c"
2021
"menu/firmware_update.c"
2122
"menu/message_dialog.c"
2223
"menu/device_information.c"

main/menu/app_inspect.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
2+
#include "app_inspect.h"
3+
#include <string.h>
4+
#include "appfs.h"
5+
#include "bsp/input.h"
6+
#include "common/display.h"
7+
#include "gui_footer.h"
8+
#include "gui_style.h"
9+
#include "icons.h"
10+
#include "menu/apps.h"
11+
#include "menu/message_dialog.h"
12+
#include "pax_gfx.h"
13+
#include "pax_matrix.h"
14+
#include "pax_text.h"
15+
#include "pax_types.h"
16+
17+
#if defined(CONFIG_BSP_TARGET_TANMATSU) || defined(CONFIG_BSP_TARGET_KONSOOL) || \
18+
defined(CONFIG_BSP_TARGET_HACKERHOTEL_2026)
19+
#define FOOTER_LEFT \
20+
((gui_header_field_t[]){{get_icon(ICON_ESC), "/"}, \
21+
{get_icon(ICON_F1), "Back"}, \
22+
{get_icon(ICON_F2), "Start"}, \
23+
{get_icon(ICON_F5), "Delete App"}}), \
24+
4
25+
#define FOOTER_RIGHT NULL, 0
26+
#define TEXT_FONT pax_font_sky_mono
27+
#define TEXT_SIZE 18
28+
#elif defined(CONFIG_BSP_TARGET_MCH2022)
29+
#define FOOTER_LEFT ((gui_header_field_t[]){{NULL, "🅱 Back"}}), 1
30+
#define FOOTER_RIGHT NULL, 0
31+
#define TEXT_FONT pax_font_sky_mono
32+
#define TEXT_SIZE 9
33+
#else
34+
#define FOOTER_LEFT NULL, 0
35+
#define FOOTER_RIGHT NULL, 0
36+
#define TEXT_FONT pax_font_sky_mono
37+
#define TEXT_SIZE 9
38+
#endif
39+
40+
static void render(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, bool partial, bool icons, app_t* app) {
41+
42+
char text_buffer[256];
43+
int line = 0;
44+
45+
if (!partial || icons) {
46+
snprintf(text_buffer, sizeof(text_buffer), "App Info: %s", app->name);
47+
render_base_screen_statusbar(buffer, theme, !partial, !partial || icons, !partial,
48+
((gui_header_field_t[]){{get_icon(ICON_DEVICE_INFO), text_buffer}}), 1,
49+
FOOTER_LEFT, FOOTER_RIGHT);
50+
}
51+
52+
if (!partial) {
53+
54+
if (app->name) {
55+
snprintf(text_buffer, sizeof(text_buffer), "Name: %s", app->name);
56+
pax_draw_text(buffer, theme->palette.color_foreground, TEXT_FONT, TEXT_SIZE, position.x0,
57+
position.y0 + (TEXT_SIZE + 2) * (line++), text_buffer);
58+
}
59+
60+
if (app->description) {
61+
snprintf(text_buffer, sizeof(text_buffer), "Description: %s", app->description);
62+
pax_draw_text(buffer, theme->palette.color_foreground, TEXT_FONT, TEXT_SIZE, position.x0,
63+
position.y0 + (TEXT_SIZE + 2) * (line++), text_buffer);
64+
}
65+
66+
if (app->author) {
67+
snprintf(text_buffer, sizeof(text_buffer), "Author: %s", app->author);
68+
pax_draw_text(buffer, theme->palette.color_foreground, TEXT_FONT, TEXT_SIZE, position.x0,
69+
position.y0 + (TEXT_SIZE + 2) * (line++), text_buffer);
70+
}
71+
72+
if (app->version) {
73+
snprintf(text_buffer, sizeof(text_buffer), "Version: %ld", app->version);
74+
pax_draw_text(buffer, theme->palette.color_foreground, TEXT_FONT, TEXT_SIZE, position.x0,
75+
position.y0 + (TEXT_SIZE + 2) * (line++), text_buffer);
76+
}
77+
78+
if (app->slug) {
79+
snprintf(text_buffer, sizeof(text_buffer), "Slug: %s", app->slug);
80+
pax_draw_text(buffer, theme->palette.color_foreground, TEXT_FONT, TEXT_SIZE, position.x0,
81+
position.y0 + (TEXT_SIZE + 2) * (line++), text_buffer);
82+
}
83+
}
84+
85+
display_blit_buffer(buffer);
86+
}
87+
88+
bool menu_app_inspect(pax_buf_t* buffer, gui_theme_t* theme, app_t* app) {
89+
QueueHandle_t input_event_queue = NULL;
90+
ESP_ERROR_CHECK(bsp_input_get_queue(&input_event_queue));
91+
92+
int header_height = theme->header.height + (theme->header.vertical_margin * 2);
93+
int footer_height = theme->footer.height + (theme->footer.vertical_margin * 2);
94+
95+
pax_vec2_t position = {
96+
.x0 = theme->menu.horizontal_margin + theme->menu.horizontal_padding,
97+
.y0 = header_height + theme->menu.vertical_margin + theme->menu.vertical_padding,
98+
.x1 = pax_buf_get_width(buffer) - theme->menu.horizontal_margin - theme->menu.horizontal_padding,
99+
.y1 = pax_buf_get_height(buffer) - footer_height - theme->menu.vertical_margin - theme->menu.vertical_padding,
100+
};
101+
102+
render(buffer, theme, position, false, false, app);
103+
104+
while (1) {
105+
bsp_input_event_t event;
106+
if (xQueueReceive(input_event_queue, &event, pdMS_TO_TICKS(1000)) == pdTRUE) {
107+
switch (event.type) {
108+
case INPUT_EVENT_TYPE_NAVIGATION: {
109+
if (event.args_navigation.state) {
110+
switch (event.args_navigation.key) {
111+
case BSP_INPUT_NAVIGATION_KEY_ESC:
112+
case BSP_INPUT_NAVIGATION_KEY_F1:
113+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_B:
114+
return false;
115+
case BSP_INPUT_NAVIGATION_KEY_F2:
116+
execute_app(buffer, theme, position, app);
117+
render(buffer, theme, position, false, false, app);
118+
break;
119+
case BSP_INPUT_NAVIGATION_KEY_F5:
120+
message_dialog_return_type_t msg_ret = message_dialog_yes_no(
121+
buffer, theme, "Delete App", "Do you really want to delete the app?");
122+
if (msg_ret == MSG_DIALOG_RETURN_OK) {
123+
appfsDeleteFile(app->slug);
124+
char text_buffer[256];
125+
snprintf(text_buffer, sizeof(text_buffer), "/sd/apps/%s", app->slug);
126+
remove(text_buffer);
127+
snprintf(text_buffer, sizeof(text_buffer), "/int/apps/%s", app->slug);
128+
remove(text_buffer);
129+
return true;
130+
}
131+
render(buffer, theme, position, false, false, app);
132+
break;
133+
default:
134+
break;
135+
}
136+
}
137+
break;
138+
}
139+
default:
140+
break;
141+
}
142+
} else {
143+
render(buffer, theme, position, false, false, app);
144+
}
145+
}
146+
}

main/menu/app_inspect.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include "app_metadata_parser.h"
4+
#include "gui_style.h"
5+
#include "pax_types.h"
6+
7+
bool menu_app_inspect(pax_buf_t* buffer, gui_theme_t* theme, app_t* app);

main/menu/apps.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <stddef.h>
33
#include <stdio.h>
44
#include <string.h>
5+
#include "app_inspect.h"
56
#include "app_metadata_parser.h"
67
#include "appfs.h"
78
#include "bsp/input.h"
@@ -11,6 +12,7 @@
1112
#include "gui_menu.h"
1213
#include "gui_style.h"
1314
#include "icons.h"
15+
#include "menu/app_inspect.h"
1416
#include "menu/message_dialog.h"
1517
#include "pax_gfx.h"
1618
#include "pax_matrix.h"
@@ -30,10 +32,10 @@ static void populate_menu(menu_t* menu, app_t** apps, size_t app_count) {
3032

3133
extern bool wifi_stack_get_task_done(void);
3234

33-
static void execute_app(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, app_t* app) {
35+
void execute_app(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, app_t* app) {
3436

3537
if (app == NULL) {
36-
message_dialog(buffer, theme, "Error", "No app selected", "OK");
38+
message_dialog_ok(buffer, theme, "Error", "No app selected");
3739
return;
3840
}
3941

@@ -54,13 +56,14 @@ static void execute_app(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t positi
5456
usb_mode_set(USB_DEBUG);
5557
esp_restart();
5658
} else {
57-
message_dialog(buffer, theme, "Error", "App not found", "OK");
59+
message_dialog_ok(buffer, theme, "Error", "App not found");
5860
}
5961
}
6062

6163
#if defined(CONFIG_BSP_TARGET_TANMATSU) || defined(CONFIG_BSP_TARGET_KONSOOL) || \
6264
defined(CONFIG_BSP_TARGET_HACKERHOTEL_2026)
63-
#define FOOTER_LEFT ((gui_header_field_t[]){{get_icon(ICON_ESC), "/"}, {get_icon(ICON_F1), "Back"}}), 2
65+
#define FOOTER_LEFT \
66+
((gui_header_field_t[]){{get_icon(ICON_ESC), "/"}, {get_icon(ICON_F1), "Back"}, {get_icon(ICON_F2), "Info"}}), 3
6467
#define FOOTER_RIGHT ((gui_header_field_t[]){{NULL, "↑ / ↓ Navigate ⏎ Start app"}}), 1
6568
#elif defined(CONFIG_BSP_TARGET_MCH2022)
6669
#define FOOTER_LEFT NULL, 0
@@ -115,6 +118,20 @@ void menu_apps(pax_buf_t* buffer, gui_theme_t* theme) {
115118
menu_free(&menu);
116119
free_list_of_apps(apps, MAX_NUM_APPS);
117120
return;
121+
case BSP_INPUT_NAVIGATION_KEY_F2:
122+
case BSP_INPUT_NAVIGATION_KEY_MENU:
123+
void* arg = menu_get_callback_args(&menu, menu_get_position(&menu));
124+
app_t* app = (app_t*)arg;
125+
if (menu_app_inspect(buffer, theme, app)) {
126+
app = NULL;
127+
menu_free(&menu);
128+
free_list_of_apps(apps, MAX_NUM_APPS);
129+
number_of_apps = create_list_of_apps(apps, MAX_NUM_APPS);
130+
menu_initialize(&menu);
131+
populate_menu(&menu, apps, number_of_apps);
132+
}
133+
render(buffer, theme, &menu, position, false, true);
134+
break;
118135
case BSP_INPUT_NAVIGATION_KEY_UP:
119136
menu_navigate_previous(&menu);
120137
render(buffer, theme, &menu, position, true, false);

main/menu/apps.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#pragma once
22

3+
#include "app_metadata_parser.h"
34
#include "gui_style.h"
45
#include "pax_types.h"
56

7+
void execute_app(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, app_t* app);
8+
69
void menu_apps(pax_buf_t* buffer, gui_theme_t* theme);

main/menu/message_dialog.c

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -183,23 +183,13 @@ void render_base_screen_statusbar(pax_buf_t* buffer, gui_theme_t* theme, bool ba
183183
header_right_count, footer_left, footer_left_count, footer_right, footer_right_count);
184184
}
185185

186-
#if defined(CONFIG_BSP_TARGET_TANMATSU) || defined(CONFIG_BSP_TARGET_KONSOOL) || \
187-
defined(CONFIG_BSP_TARGET_HACKERHOTEL_2026)
188-
#define FOOTER_LEFT ((gui_header_field_t[]){{get_icon(ICON_ESC), "/"}, {get_icon(ICON_F1), (char*)action_text}}), 2
189-
#define FOOTER_RIGHT NULL, 0
190-
#elif defined(CONFIG_BSP_TARGET_MCH2022)
191-
#define FOOTER_LEFT ((gui_header_field_t[]){{NULL, "🅱"}, {NULL, (char*)action_text}}), 2
192186
#define FOOTER_RIGHT NULL, 0
193-
#else
194-
#define FOOTER_LEFT NULL, 0
195-
#define FOOTER_RIGHT NULL, 0
196-
#endif
197187

198188
static void render(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, const char* title, const char* message,
199-
const char* action_text, bool partial, bool icons) {
189+
gui_header_field_t* headers, int header_count, bool partial, bool icons) {
200190
if (!partial || icons) {
201191
render_base_screen_statusbar(buffer, theme, !partial, !partial || icons, !partial,
202-
((gui_header_field_t[]){{get_icon(ICON_ERROR), title}}), 1, FOOTER_LEFT,
192+
((gui_header_field_t[]){{get_icon(ICON_ERROR), title}}), 1, headers, header_count,
203193
FOOTER_RIGHT);
204194
}
205195
if (!partial) {
@@ -209,8 +199,8 @@ static void render(pax_buf_t* buffer, gui_theme_t* theme, pax_vec2_t position, c
209199
display_blit_buffer(buffer);
210200
}
211201

212-
void message_dialog(pax_buf_t* buffer, gui_theme_t* theme, const char* title, const char* message,
213-
const char* action_text) {
202+
bsp_input_navigation_key_t message_dialog(pax_buf_t* buffer, gui_theme_t* theme, const char* title, const char* message,
203+
gui_header_field_t* headers, int header_count) {
214204
QueueHandle_t input_event_queue = NULL;
215205
ESP_ERROR_CHECK(bsp_input_get_queue(&input_event_queue));
216206

@@ -224,29 +214,74 @@ void message_dialog(pax_buf_t* buffer, gui_theme_t* theme, const char* title, co
224214
.y1 = pax_buf_get_height(buffer) - footer_height - theme->menu.vertical_margin - theme->menu.vertical_padding,
225215
};
226216

227-
render(buffer, theme, position, title, message, action_text, false, true);
217+
render(buffer, theme, position, title, message, headers, header_count, false, true);
228218
while (1) {
229219
bsp_input_event_t event;
230220
if (xQueueReceive(input_event_queue, &event, pdMS_TO_TICKS(1000)) == pdTRUE) {
231221
switch (event.type) {
232222
case INPUT_EVENT_TYPE_NAVIGATION: {
233-
if (event.args_navigation.state) {
234-
switch (event.args_navigation.key) {
235-
case BSP_INPUT_NAVIGATION_KEY_ESC:
236-
case BSP_INPUT_NAVIGATION_KEY_F1:
237-
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_B:
238-
return;
239-
default:
240-
break;
241-
}
242-
}
223+
if (event.args_navigation.state) return event.args_navigation.key;
243224
break;
244225
}
245226
default:
246227
break;
247228
}
248229
} else {
249-
render(buffer, theme, position, title, message, action_text, true, true);
230+
render(buffer, theme, position, title, message, headers, header_count, true, true);
231+
}
232+
}
233+
}
234+
235+
message_dialog_return_type_t message_dialog_ok(pax_buf_t* buffer, gui_theme_t* theme, const char* title,
236+
const char* message) {
237+
bsp_input_navigation_key_t key;
238+
while (1) {
239+
key = message_dialog(buffer, theme, title, message, MESSAGE_DIALOG_FOOTER_OK);
240+
switch (key) {
241+
case BSP_INPUT_NAVIGATION_KEY_ESC:
242+
case BSP_INPUT_NAVIGATION_KEY_F1:
243+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_A:
244+
return MSG_DIALOG_RETURN_OK;
245+
default:
246+
}
247+
}
248+
}
249+
250+
message_dialog_return_type_t message_dialog_yes_no(pax_buf_t* buffer, gui_theme_t* theme, const char* title,
251+
const char* message) {
252+
bsp_input_navigation_key_t key;
253+
while (1) {
254+
key = message_dialog(buffer, theme, title, message, MESSAGE_DIALOG_FOOTER_YES_NO);
255+
switch (key) {
256+
case BSP_INPUT_NAVIGATION_KEY_ESC:
257+
case BSP_INPUT_NAVIGATION_KEY_F1:
258+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_B:
259+
return MSG_DIALOG_RETURN_NO;
260+
case BSP_INPUT_NAVIGATION_KEY_F4:
261+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_A:
262+
return MSG_DIALOG_RETURN_OK;
263+
default:
264+
}
265+
}
266+
}
267+
268+
message_dialog_return_type_t message_dialog_yes_no_cancel(pax_buf_t* buffer, gui_theme_t* theme, const char* title,
269+
const char* message) {
270+
bsp_input_navigation_key_t key;
271+
while (1) {
272+
key = message_dialog(buffer, theme, title, message, MESSAGE_DIALOG_FOOTER_YES_NO_CANCEL);
273+
switch (key) {
274+
case BSP_INPUT_NAVIGATION_KEY_ESC:
275+
case BSP_INPUT_NAVIGATION_KEY_F1:
276+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_B:
277+
return MSG_DIALOG_RETURN_NO;
278+
case BSP_INPUT_NAVIGATION_KEY_F4:
279+
case BSP_INPUT_NAVIGATION_KEY_GAMEPAD_A:
280+
return MSG_DIALOG_RETURN_OK;
281+
case BSP_INPUT_NAVIGATION_KEY_F6:
282+
case BSP_INPUT_NAVIGATION_KEY_MENU:
283+
return MSG_DIALOG_RETURN_CANCEL;
284+
default:
250285
}
251286
}
252287
}

0 commit comments

Comments
 (0)