flip_store_callback.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. #include <callback/flip_store_callback.h>
  2. bool flip_store_app_does_exist = false;
  3. uint32_t selected_firmware_index = 0;
  4. // Callback for drawing the main screen
  5. void flip_store_view_draw_callback_main(Canvas *canvas, void *model)
  6. {
  7. UNUSED(model);
  8. canvas_set_font(canvas, FontSecondary);
  9. if (fhttp.state == INACTIVE)
  10. {
  11. canvas_draw_str(canvas, 0, 7, "Wifi Dev Board disconnected.");
  12. canvas_draw_str(canvas, 0, 17, "Please connect to the board.");
  13. canvas_draw_str(canvas, 0, 32, "If your board is connected,");
  14. canvas_draw_str(canvas, 0, 42, "make sure you have flashed");
  15. canvas_draw_str(canvas, 0, 52, "your WiFi Devboard with the");
  16. canvas_draw_str(canvas, 0, 62, "latest FlipperHTTP flash.");
  17. return;
  18. }
  19. if (!flip_store_sent_request)
  20. {
  21. flip_store_sent_request = true;
  22. if (!flip_store_install_app(canvas, categories[flip_store_category_index]))
  23. {
  24. canvas_clear(canvas);
  25. canvas_draw_str(canvas, 0, 10, "Failed to install app.");
  26. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  27. }
  28. }
  29. else
  30. {
  31. if (flip_store_success)
  32. {
  33. if (fhttp.state == RECEIVING)
  34. {
  35. canvas_clear(canvas);
  36. canvas_draw_str(canvas, 0, 10, "Downloading app...");
  37. canvas_draw_str(canvas, 0, 60, "Please wait...");
  38. return;
  39. }
  40. else if (fhttp.state == IDLE)
  41. {
  42. canvas_clear(canvas);
  43. canvas_draw_str(canvas, 0, 10, "App installed successfully.");
  44. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  45. }
  46. }
  47. else
  48. {
  49. canvas_clear(canvas);
  50. canvas_draw_str(canvas, 0, 10, "Failed to install app.");
  51. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  52. }
  53. }
  54. }
  55. // Function to draw the firmware download screen
  56. void flip_store_view_draw_callback_firmware(Canvas *canvas, void *model)
  57. {
  58. UNUSED(model);
  59. // Check if the HTTP state is inactive
  60. if (fhttp.state == INACTIVE)
  61. {
  62. canvas_set_font(canvas, FontSecondary);
  63. canvas_draw_str(canvas, 0, 7, "Wifi Dev Board disconnected.");
  64. canvas_draw_str(canvas, 0, 17, "Please connect to the board.");
  65. canvas_draw_str(canvas, 0, 32, "If your board is connected,");
  66. canvas_draw_str(canvas, 0, 42, "make sure you have flashed");
  67. canvas_draw_str(canvas, 0, 52, "your WiFi Devboard with the");
  68. canvas_draw_str(canvas, 0, 62, "latest FlipperHTTP flash.");
  69. return;
  70. }
  71. // Set font and clear the canvas for the loading state
  72. canvas_set_font(canvas, FontSecondary);
  73. canvas_clear(canvas);
  74. canvas_draw_str(canvas, 0, 10, "Loading...");
  75. // Handle first firmware file
  76. if (!sent_firmware_request)
  77. {
  78. sent_firmware_request = true;
  79. firmware_request_success = flip_store_get_firmware_file(
  80. firmwares[selected_firmware_index].links[0],
  81. firmwares[selected_firmware_index].name,
  82. strrchr(firmwares[selected_firmware_index].links[0], '/') + 1);
  83. if (!firmware_request_success)
  84. {
  85. canvas_set_font(canvas, FontSecondary);
  86. canvas_clear(canvas);
  87. flip_store_request_error(canvas);
  88. }
  89. return;
  90. }
  91. else if (sent_firmware_request && !firmware_download_success)
  92. {
  93. if (!firmware_request_success || fhttp.state == ISSUE)
  94. {
  95. canvas_set_font(canvas, FontSecondary);
  96. canvas_clear(canvas);
  97. flip_store_request_error(canvas);
  98. }
  99. else if (fhttp.state == RECEIVING)
  100. {
  101. canvas_set_font(canvas, FontSecondary);
  102. canvas_clear(canvas);
  103. canvas_draw_str(canvas, 0, 10, "Downloading file 1...");
  104. canvas_draw_str(canvas, 0, 60, "Please wait...");
  105. }
  106. else if (fhttp.state == IDLE)
  107. {
  108. canvas_set_font(canvas, FontSecondary);
  109. canvas_clear(canvas);
  110. canvas_draw_str(canvas, 0, 10, "Success");
  111. canvas_draw_str(canvas, 0, 60, "Downloading the next file now.");
  112. firmware_download_success = true;
  113. }
  114. return;
  115. }
  116. // Handle second firmware file
  117. if (firmware_download_success && !sent_firmware_request_2)
  118. {
  119. sent_firmware_request_2 = true;
  120. firmware_request_success_2 = flip_store_get_firmware_file(
  121. firmwares[selected_firmware_index].links[1],
  122. firmwares[selected_firmware_index].name,
  123. strrchr(firmwares[selected_firmware_index].links[1], '/') + 1);
  124. if (!firmware_request_success_2)
  125. {
  126. canvas_set_font(canvas, FontSecondary);
  127. canvas_clear(canvas);
  128. flip_store_request_error(canvas);
  129. }
  130. return;
  131. }
  132. else if (sent_firmware_request_2 && !firmware_download_success_2)
  133. {
  134. if (!firmware_request_success_2 || fhttp.state == ISSUE)
  135. {
  136. canvas_set_font(canvas, FontSecondary);
  137. canvas_clear(canvas);
  138. flip_store_request_error(canvas);
  139. }
  140. else if (fhttp.state == RECEIVING)
  141. {
  142. canvas_set_font(canvas, FontSecondary);
  143. canvas_clear(canvas);
  144. canvas_draw_str(canvas, 0, 10, "Downloading file 2...");
  145. canvas_draw_str(canvas, 0, 60, "Please wait...");
  146. }
  147. else if (fhttp.state == IDLE)
  148. {
  149. canvas_set_font(canvas, FontSecondary);
  150. canvas_clear(canvas);
  151. canvas_draw_str(canvas, 0, 10, "Success");
  152. canvas_draw_str(canvas, 0, 60, "Downloading the next file now.");
  153. firmware_download_success_2 = true;
  154. }
  155. return;
  156. }
  157. // Handle third firmware file
  158. if (firmware_download_success && firmware_download_success_2 && !sent_firmware_request_3)
  159. {
  160. sent_firmware_request_3 = true;
  161. firmware_request_success_3 = flip_store_get_firmware_file(
  162. firmwares[selected_firmware_index].links[2],
  163. firmwares[selected_firmware_index].name,
  164. strrchr(firmwares[selected_firmware_index].links[2], '/') + 1);
  165. if (!firmware_request_success_3)
  166. {
  167. canvas_set_font(canvas, FontSecondary);
  168. canvas_clear(canvas);
  169. flip_store_request_error(canvas);
  170. }
  171. return;
  172. }
  173. else if (sent_firmware_request_3 && !firmware_download_success_3)
  174. {
  175. if (!firmware_request_success_3 || fhttp.state == ISSUE)
  176. {
  177. canvas_set_font(canvas, FontSecondary);
  178. canvas_clear(canvas);
  179. flip_store_request_error(canvas);
  180. }
  181. else if (fhttp.state == RECEIVING)
  182. {
  183. canvas_set_font(canvas, FontSecondary);
  184. canvas_clear(canvas);
  185. canvas_draw_str(canvas, 0, 10, "Downloading file 3...");
  186. canvas_draw_str(canvas, 0, 60, "Please wait...");
  187. }
  188. else if (fhttp.state == IDLE)
  189. {
  190. canvas_set_font(canvas, FontSecondary);
  191. canvas_clear(canvas);
  192. canvas_draw_str(canvas, 0, 10, "Success");
  193. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  194. firmware_download_success_3 = true;
  195. }
  196. return;
  197. }
  198. // All files downloaded successfully
  199. if (firmware_download_success && firmware_download_success_2 && firmware_download_success_3)
  200. {
  201. canvas_set_font(canvas, FontSecondary);
  202. canvas_clear(canvas);
  203. canvas_draw_str(canvas, 0, 10, "Files downloaded successfully.");
  204. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  205. }
  206. }
  207. // Function to draw the message on the canvas with word wrapping
  208. void draw_description(Canvas *canvas, const char *description, int x, int y)
  209. {
  210. if (description == NULL || strlen(description) == 0)
  211. {
  212. FURI_LOG_E(TAG, "User message is NULL.");
  213. return;
  214. }
  215. if (!canvas)
  216. {
  217. FURI_LOG_E(TAG, "Canvas is NULL.");
  218. return;
  219. }
  220. size_t msg_length = strlen(description);
  221. size_t start = 0;
  222. int line_num = 0;
  223. char line[MAX_LINE_LENGTH + 1]; // Buffer for the current line (+1 for null terminator)
  224. while (start < msg_length && line_num < 4)
  225. {
  226. size_t remaining = msg_length - start;
  227. size_t len = (remaining > MAX_LINE_LENGTH) ? MAX_LINE_LENGTH : remaining;
  228. if (remaining > MAX_LINE_LENGTH)
  229. {
  230. // Find the last space within the first 'len' characters
  231. size_t last_space = len;
  232. while (last_space > 0 && description[start + last_space - 1] != ' ')
  233. {
  234. last_space--;
  235. }
  236. if (last_space > 0)
  237. {
  238. len = last_space; // Adjust len to the position of the last space
  239. }
  240. }
  241. // Copy the substring to 'line' and null-terminate it
  242. memcpy(line, description + start, len);
  243. line[len] = '\0'; // Ensure the string is null-terminated
  244. // Draw the string on the canvas
  245. // Adjust the y-coordinate based on the line number
  246. canvas_draw_str_aligned(canvas, x, y + line_num * 10, AlignLeft, AlignTop, line);
  247. // Update the start position for the next line
  248. start += len;
  249. // Skip any spaces to avoid leading spaces on the next line
  250. while (start < msg_length && description[start] == ' ')
  251. {
  252. start++;
  253. }
  254. // Increment the line number
  255. line_num++;
  256. }
  257. }
  258. void flip_store_view_draw_callback_app_list(Canvas *canvas, void *model)
  259. {
  260. UNUSED(model);
  261. canvas_clear(canvas);
  262. canvas_set_font(canvas, FontPrimary);
  263. char title[30];
  264. snprintf(title, 30, "%s (v.%s)", flip_catalog[app_selected_index].app_name, flip_catalog[app_selected_index].app_version);
  265. canvas_draw_str(canvas, 0, 10, title);
  266. canvas_set_font(canvas, FontSecondary);
  267. draw_description(canvas, flip_catalog[app_selected_index].app_description, 0, 13);
  268. if (flip_store_app_does_exist)
  269. {
  270. canvas_draw_icon(canvas, 0, 53, &I_ButtonLeft_4x7);
  271. canvas_draw_str_aligned(canvas, 7, 54, AlignLeft, AlignTop, "Delete");
  272. canvas_draw_icon(canvas, 45, 53, &I_ButtonBACK_10x8);
  273. canvas_draw_str_aligned(canvas, 57, 54, AlignLeft, AlignTop, "Back");
  274. }
  275. else
  276. {
  277. canvas_draw_icon(canvas, 0, 53, &I_ButtonBACK_10x8);
  278. canvas_draw_str_aligned(canvas, 12, 54, AlignLeft, AlignTop, "Back");
  279. }
  280. canvas_draw_icon(canvas, 90, 53, &I_ButtonRight_4x7);
  281. canvas_draw_str_aligned(canvas, 97, 54, AlignLeft, AlignTop, "Install");
  282. }
  283. bool flip_store_input_callback(InputEvent *event, void *context)
  284. {
  285. FlipStoreApp *app = (FlipStoreApp *)context;
  286. if (!app)
  287. {
  288. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  289. return false;
  290. }
  291. if (event->type == InputTypeShort)
  292. {
  293. if (event->key == InputKeyLeft && flip_store_app_does_exist)
  294. {
  295. // Left button clicked, delete the app
  296. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppDelete);
  297. return true;
  298. }
  299. if (event->key == InputKeyRight)
  300. {
  301. // Right button clicked, download the app
  302. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewMain);
  303. return true;
  304. }
  305. }
  306. else if (event->type == InputTypePress)
  307. {
  308. if (event->key == InputKeyBack)
  309. {
  310. // Back button clicked, switch to the previous view.
  311. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
  312. return true;
  313. }
  314. }
  315. return false;
  316. }
  317. void flip_store_text_updated_ssid(void *context)
  318. {
  319. FlipStoreApp *app = (FlipStoreApp *)context;
  320. if (!app)
  321. {
  322. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  323. return;
  324. }
  325. // store the entered text
  326. strncpy(app->uart_text_input_buffer_ssid, app->uart_text_input_temp_buffer_ssid, app->uart_text_input_buffer_size_ssid);
  327. // Ensure null-termination
  328. app->uart_text_input_buffer_ssid[app->uart_text_input_buffer_size_ssid - 1] = '\0';
  329. // update the variable item text
  330. if (app->variable_item_ssid)
  331. {
  332. variable_item_set_current_value_text(app->variable_item_ssid, app->uart_text_input_buffer_ssid);
  333. }
  334. // save the settings
  335. save_settings(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_pass);
  336. // if SSID and PASS are not empty, connect to the WiFi
  337. if (strlen(app->uart_text_input_buffer_ssid) > 0 && strlen(app->uart_text_input_buffer_pass) > 0)
  338. {
  339. // save wifi settings
  340. if (!flipper_http_save_wifi(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_pass))
  341. {
  342. FURI_LOG_E(TAG, "Failed to save WiFi settings");
  343. }
  344. }
  345. // switch to the settings view
  346. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSettings);
  347. }
  348. void flip_store_text_updated_pass(void *context)
  349. {
  350. FlipStoreApp *app = (FlipStoreApp *)context;
  351. if (!app)
  352. {
  353. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  354. return;
  355. }
  356. // store the entered text
  357. strncpy(app->uart_text_input_buffer_pass, app->uart_text_input_temp_buffer_pass, app->uart_text_input_buffer_size_pass);
  358. // Ensure null-termination
  359. app->uart_text_input_buffer_pass[app->uart_text_input_buffer_size_pass - 1] = '\0';
  360. // update the variable item text
  361. if (app->variable_item_pass)
  362. {
  363. variable_item_set_current_value_text(app->variable_item_pass, app->uart_text_input_buffer_pass);
  364. }
  365. // save the settings
  366. save_settings(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_pass);
  367. // if SSID and PASS are not empty, connect to the WiFi
  368. if (strlen(app->uart_text_input_buffer_ssid) > 0 && strlen(app->uart_text_input_buffer_pass) > 0)
  369. {
  370. // save wifi settings
  371. if (!flipper_http_save_wifi(app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_pass))
  372. {
  373. FURI_LOG_E(TAG, "Failed to save WiFi settings");
  374. }
  375. }
  376. // switch to the settings view
  377. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSettings);
  378. }
  379. uint32_t callback_to_submenu(void *context)
  380. {
  381. if (!context)
  382. {
  383. FURI_LOG_E(TAG, "Context is NULL");
  384. return VIEW_NONE;
  385. }
  386. UNUSED(context);
  387. firmware_free();
  388. return FlipStoreViewSubmenu;
  389. }
  390. uint32_t callback_to_submenu_options(void *context)
  391. {
  392. if (!context)
  393. {
  394. FURI_LOG_E(TAG, "Context is NULL");
  395. return VIEW_NONE;
  396. }
  397. UNUSED(context);
  398. firmware_free();
  399. return FlipStoreViewSubmenuOptions;
  400. }
  401. uint32_t callback_to_firmware_list(void *context)
  402. {
  403. if (!context)
  404. {
  405. FURI_LOG_E(TAG, "Context is NULL");
  406. return VIEW_NONE;
  407. }
  408. UNUSED(context);
  409. sent_firmware_request = false;
  410. sent_firmware_request_2 = false;
  411. sent_firmware_request_3 = false;
  412. //
  413. firmware_request_success = false;
  414. firmware_request_success_2 = false;
  415. firmware_request_success_3 = false;
  416. //
  417. firmware_download_success = false;
  418. firmware_download_success_2 = false;
  419. firmware_download_success_3 = false;
  420. return FlipStoreViewFirmwares;
  421. }
  422. uint32_t callback_to_app_list(void *context)
  423. {
  424. if (!context)
  425. {
  426. FURI_LOG_E(TAG, "Context is NULL");
  427. return VIEW_NONE;
  428. }
  429. UNUSED(context);
  430. flip_store_sent_request = false;
  431. flip_store_success = false;
  432. flip_store_saved_data = false;
  433. flip_store_saved_success = false;
  434. flip_store_app_does_exist = false;
  435. sent_firmware_request = false;
  436. return FlipStoreViewAppList;
  437. }
  438. void settings_item_selected(void *context, uint32_t index)
  439. {
  440. FlipStoreApp *app = (FlipStoreApp *)context;
  441. if (!app)
  442. {
  443. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  444. return;
  445. }
  446. switch (index)
  447. {
  448. case 0: // Input SSID
  449. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewTextInputSSID);
  450. break;
  451. case 1: // Input Password
  452. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewTextInputPass);
  453. break;
  454. default:
  455. FURI_LOG_E(TAG, "Unknown configuration item index");
  456. break;
  457. }
  458. }
  459. void dialog_delete_callback(DialogExResult result, void *context)
  460. {
  461. furi_assert(context);
  462. FlipStoreApp *app = (FlipStoreApp *)context;
  463. if (result == DialogExResultLeft) // No
  464. {
  465. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
  466. }
  467. else if (result == DialogExResultRight)
  468. {
  469. // delete the app then return to the app list
  470. if (!delete_app(flip_catalog[app_selected_index].app_id, categories[flip_store_category_index]))
  471. {
  472. // pop up a message
  473. popup_set_header(app->popup, "[ERROR]", 0, 0, AlignLeft, AlignTop);
  474. popup_set_text(app->popup, "Issue deleting app.", 0, 50, AlignLeft, AlignTop);
  475. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewPopup);
  476. furi_delay_ms(2000); // delay for 2 seconds
  477. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
  478. }
  479. else
  480. {
  481. // pop up a message
  482. popup_set_header(app->popup, "[SUCCESS]", 0, 0, AlignLeft, AlignTop);
  483. popup_set_text(app->popup, "App deleted successfully.", 0, 50, AlignLeft, AlignTop);
  484. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewPopup);
  485. furi_delay_ms(2000); // delay for 2 seconds
  486. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
  487. }
  488. }
  489. }
  490. void dialog_firmware_callback(DialogExResult result, void *context)
  491. {
  492. furi_assert(context);
  493. FlipStoreApp *app = (FlipStoreApp *)context;
  494. if (result == DialogExResultLeft) // No
  495. {
  496. // switch to the firmware list
  497. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
  498. }
  499. else if (result == DialogExResultRight)
  500. {
  501. // download the firmware then return to the firmware list
  502. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwareDownload);
  503. }
  504. }
  505. void popup_callback(void *context)
  506. {
  507. FlipStoreApp *app = (FlipStoreApp *)context;
  508. if (!app)
  509. {
  510. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  511. return;
  512. }
  513. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSubmenu);
  514. }
  515. uint32_t callback_exit_app(void *context)
  516. {
  517. // Exit the application
  518. if (!context)
  519. {
  520. FURI_LOG_E(TAG, "Context is NULL");
  521. return VIEW_NONE;
  522. }
  523. UNUSED(context);
  524. return VIEW_NONE; // Return VIEW_NONE to exit the app
  525. }
  526. void callback_submenu_choices(void *context, uint32_t index)
  527. {
  528. FlipStoreApp *app = (FlipStoreApp *)context;
  529. if (!app)
  530. {
  531. FURI_LOG_E(TAG, "FlipStoreApp is NULL");
  532. return;
  533. }
  534. switch (index)
  535. {
  536. case FlipStoreSubmenuIndexMain:
  537. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewMain);
  538. break;
  539. case FlipStoreSubmenuIndexAbout:
  540. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAbout);
  541. break;
  542. case FlipStoreSubmenuIndexSettings:
  543. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSettings);
  544. break;
  545. case FlipStoreSubmenuIndexOptions:
  546. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSubmenuOptions);
  547. break;
  548. case FlipStoreSubmenuIndexAppList:
  549. flip_store_category_index = 0;
  550. flip_store_app_does_exist = false;
  551. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
  552. break;
  553. case FlipStoreSubmenuIndexFirmwares:
  554. if (!app->submenu_firmwares)
  555. {
  556. FURI_LOG_E(TAG, "Submenu firmwares is NULL");
  557. return;
  558. }
  559. firmwares = firmware_alloc();
  560. if (firmwares == NULL)
  561. {
  562. FURI_LOG_E(TAG, "Failed to allocate memory for firmwares");
  563. return;
  564. }
  565. submenu_reset(app->submenu_firmwares);
  566. submenu_set_header(app->submenu_firmwares, "ESP32 Firmwares");
  567. for (int i = 0; i < FIRMWARE_COUNT; i++)
  568. {
  569. submenu_add_item(app->submenu_firmwares, firmwares[i].name, FlipStoreSubmenuIndexStartFirmwares + i, callback_submenu_choices, app);
  570. }
  571. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
  572. break;
  573. case FlipStoreSubmenuIndexAppListBluetooth:
  574. flip_store_category_index = 0;
  575. flip_store_app_does_exist = false;
  576. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListBluetooth, "Bluetooth", &app->submenu_app_list_bluetooth));
  577. break;
  578. case FlipStoreSubmenuIndexAppListGames:
  579. flip_store_category_index = 1;
  580. flip_store_app_does_exist = false;
  581. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListGames, "Games", &app->submenu_app_list_games));
  582. break;
  583. case FlipStoreSubmenuIndexAppListGPIO:
  584. flip_store_category_index = 2;
  585. flip_store_app_does_exist = false;
  586. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListGPIO, "GPIO", &app->submenu_app_list_gpio));
  587. break;
  588. case FlipStoreSubmenuIndexAppListInfrared:
  589. flip_store_category_index = 3;
  590. flip_store_app_does_exist = false;
  591. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListInfrared, "Infrared", &app->submenu_app_list_infrared));
  592. break;
  593. case FlipStoreSubmenuIndexAppListiButton:
  594. flip_store_category_index = 4;
  595. flip_store_app_does_exist = false;
  596. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListiButton, "iButton", &app->submenu_app_list_ibutton));
  597. break;
  598. case FlipStoreSubmenuIndexAppListMedia:
  599. flip_store_category_index = 5;
  600. flip_store_app_does_exist = false;
  601. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListMedia, "Media", &app->submenu_app_list_media));
  602. break;
  603. case FlipStoreSubmenuIndexAppListNFC:
  604. flip_store_category_index = 6;
  605. flip_store_app_does_exist = false;
  606. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListNFC, "NFC", &app->submenu_app_list_nfc));
  607. break;
  608. case FlipStoreSubmenuIndexAppListRFID:
  609. flip_store_category_index = 7;
  610. flip_store_app_does_exist = false;
  611. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListRFID, "RFID", &app->submenu_app_list_rfid));
  612. break;
  613. case FlipStoreSubmenuIndexAppListSubGHz:
  614. flip_store_category_index = 8;
  615. flip_store_app_does_exist = false;
  616. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListSubGHz, "Sub-GHz", &app->submenu_app_list_subghz));
  617. break;
  618. case FlipStoreSubmenuIndexAppListTools:
  619. flip_store_category_index = 9;
  620. flip_store_app_does_exist = false;
  621. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListTools, "Tools", &app->submenu_app_list_tools));
  622. break;
  623. case FlipStoreSubmenuIndexAppListUSB:
  624. flip_store_category_index = 10;
  625. flip_store_app_does_exist = false;
  626. view_dispatcher_switch_to_view(app->view_dispatcher, flip_store_handle_app_list(app, FlipStoreViewAppListUSB, "USB", &app->submenu_app_list_usb));
  627. break;
  628. default:
  629. // Check if the index is within the firmwares list range
  630. if (index >= FlipStoreSubmenuIndexStartFirmwares && index < FlipStoreSubmenuIndexStartFirmwares + 3)
  631. {
  632. // Get the firmware index
  633. uint32_t firmware_index = index - FlipStoreSubmenuIndexStartFirmwares;
  634. // Check if the firmware index is valid
  635. if ((int)firmware_index >= 0 && firmware_index < FIRMWARE_COUNT)
  636. {
  637. // Get the firmware name
  638. selected_firmware_index = firmware_index;
  639. // Switch to the firmware download view
  640. dialog_ex_set_header(app->dialog_firmware, firmwares[firmware_index].name, 0, 0, AlignLeft, AlignTop);
  641. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwareDialog);
  642. }
  643. else
  644. {
  645. FURI_LOG_E(TAG, "Invalid firmware index");
  646. popup_set_header(app->popup, "[ERROR]", 0, 0, AlignLeft, AlignTop);
  647. popup_set_text(app->popup, "Issue parsing firmwarex", 0, 50, AlignLeft, AlignTop);
  648. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewPopup);
  649. }
  650. }
  651. // Check if the index is within the app list range
  652. else if (index >= FlipStoreSubmenuIndexStartAppList && index < FlipStoreSubmenuIndexStartAppList + MAX_APP_COUNT)
  653. {
  654. // Get the app index
  655. uint32_t app_index = index - FlipStoreSubmenuIndexStartAppList;
  656. // Check if the app index is valid
  657. if ((int)app_index >= 0 && app_index < MAX_APP_COUNT)
  658. {
  659. // Get the app name
  660. char *app_name = flip_catalog[app_index].app_name;
  661. // Check if the app name is valid
  662. if (app_name != NULL && strlen(app_name) > 0)
  663. {
  664. app_selected_index = app_index;
  665. flip_store_app_does_exist = app_exists(flip_catalog[app_selected_index].app_id, categories[flip_store_category_index]);
  666. view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppInfo);
  667. }
  668. else
  669. {
  670. FURI_LOG_E(TAG, "Invalid app name");
  671. }
  672. }
  673. else
  674. {
  675. FURI_LOG_E(TAG, "Invalid app index");
  676. }
  677. }
  678. else
  679. {
  680. FURI_LOG_E(TAG, "Unknown submenu index");
  681. }
  682. break;
  683. }
  684. }