فهرست منبع

FlipStore - v0.6

- Updated app layout
- Added an option to download Developer Board firmware (Black Magic, FlipperHTTP, and Marauder)
jblanked 1 سال پیش
والد
کامیت
4d2a289721

+ 5 - 5
README.md

@@ -4,13 +4,13 @@ Download Flipper Zero apps directly to your Flipper Zero using WiFi. You no long
 ## Features
 ## Features
 - App Catalog
 - App Catalog
 - Install Apps
 - Install Apps
-- Delete Apps (coming soon)
+- Delete Apps 
+- Install Developer Board Flashes
 - Install Custom Apps (coming soon)
 - Install Custom Apps (coming soon)
-- Install Devboard Flashes (coming soon)
 - Install Official Firmware (coming soon)
 - Install Official Firmware (coming soon)
 
 
 ## Installation
 ## Installation
-1. Flash your WiFi Devboard: https://github.com/jblanked/FlipperHTTP
+1. Flash your WiFi Dveloper Board or Raspberry Pi Pico W: https://github.com/jblanked/FlipperHTTP
 2. Install the app.
 2. Install the app.
 3. Enjoy :D
 3. Enjoy :D
 
 
@@ -47,9 +47,9 @@ Download Flipper Zero apps directly to your Flipper Zero using WiFi. You no long
 This is a big task, and I welcome all contributors, especially developers interested in animations and graphics. Fork the repository, create a pull request, and I will review your edits.
 This is a big task, and I welcome all contributors, especially developers interested in animations and graphics. Fork the repository, create a pull request, and I will review your edits.
 
 
 ## Known Bugs
 ## Known Bugs
-1. Clicking the catalog results in an "Out of Memory" error.
+1. Clicking a category in the app catalog results in an "Out of Memory" error.
    - This issue has been addressed, but it may still occur. If it does, restart the app.
    - This issue has been addressed, but it may still occur. If it does, restart the app.
 2. The app file is corrupted.
 2. The app file is corrupted.
    - This is likely due to an error parsing the data. Restart the app and wait until the green LED light turns off after downloading the app before exiting the view. If this happens more than three times, the current version of FlipStore may not be able to download that app successfully.
    - This is likely due to an error parsing the data. Restart the app and wait until the green LED light turns off after downloading the app before exiting the view. If this happens more than three times, the current version of FlipStore may not be able to download that app successfully.
-3. The app is frozen on the "Installing" or "Receiving data" screen. 
+3. The app is frozen on the "Installing", "Loading", or "Receiving data" screen. 
    - If it there LED is not on and it's been more than 5 seconds, restart your Flipper Zero with the devboard plugged in.
    - If it there LED is not on and it's been more than 5 seconds, restart your Flipper Zero with the devboard plugged in.

+ 27 - 7
alloc/flip_store_alloc.c

@@ -47,6 +47,10 @@ FlipStoreApp *flip_store_app_alloc()
     {
     {
         return NULL;
         return NULL;
     }
     }
+    if (!easy_flipper_set_view(&app->view_firmware_download, FlipStoreViewFirmwareDownload, flip_store_view_draw_callback_firmware, NULL, callback_to_firmware_list, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
 
 
     // Widget
     // Widget
     if (!easy_flipper_set_widget(
     if (!easy_flipper_set_widget(
@@ -78,7 +82,7 @@ FlipStoreApp *flip_store_app_alloc()
             "No",
             "No",
             "Yes",
             "Yes",
             NULL,
             NULL,
-            dialog_callback,
+            dialog_delete_callback,
             callback_to_app_list,
             callback_to_app_list,
             &app->view_dispatcher,
             &app->view_dispatcher,
             app))
             app))
@@ -86,6 +90,26 @@ FlipStoreApp *flip_store_app_alloc()
         return NULL;
         return NULL;
     }
     }
 
 
+    if (!easy_flipper_set_dialog_ex(
+            &app->dialog_firmware,
+            FlipStoreViewFirmwareDialog,
+            "Download Firmware",
+            0,
+            0,
+            "Are you sure you want to\ndownload this firmware?",
+            0,
+            10,
+            "No",
+            "Yes",
+            NULL,
+            dialog_firmware_callback,
+            callback_to_firmware_list,
+            &app->view_dispatcher,
+            app))
+    {
+        return NULL;
+    }
+
     // Text Input
     // Text Input
     if (!easy_flipper_set_uart_text_input(&app->uart_text_input_ssid, FlipStoreViewTextInputSSID, "Enter SSID", app->uart_text_input_temp_buffer_ssid, app->uart_text_input_buffer_size_ssid, flip_store_text_updated_ssid, callback_to_submenu, &app->view_dispatcher, app))
     if (!easy_flipper_set_uart_text_input(&app->uart_text_input_ssid, FlipStoreViewTextInputSSID, "Enter SSID", app->uart_text_input_temp_buffer_ssid, app->uart_text_input_buffer_size_ssid, flip_store_text_updated_ssid, callback_to_submenu, &app->view_dispatcher, app))
     {
     {
@@ -105,7 +129,7 @@ FlipStoreApp *flip_store_app_alloc()
     app->variable_item_pass = variable_item_list_add(app->variable_item_list, "Password", 0, NULL, NULL);
     app->variable_item_pass = variable_item_list_add(app->variable_item_list, "Password", 0, NULL, NULL);
 
 
     // Submenu
     // Submenu
-    if (!easy_flipper_set_submenu(&app->submenu_main, FlipStoreViewSubmenu, "FlipStore v0.5", callback_exit_app, &app->view_dispatcher))
+    if (!easy_flipper_set_submenu(&app->submenu_main, FlipStoreViewSubmenu, "FlipStore v0.6", callback_exit_app, &app->view_dispatcher))
     {
     {
         return NULL;
         return NULL;
     }
     }
@@ -172,11 +196,7 @@ FlipStoreApp *flip_store_app_alloc()
     //
     //
     submenu_add_item(app->submenu_options, "App Catalog", FlipStoreSubmenuIndexAppList, callback_submenu_choices, app);
     submenu_add_item(app->submenu_options, "App Catalog", FlipStoreSubmenuIndexAppList, callback_submenu_choices, app);
     submenu_add_item(app->submenu_options, "ESP32 Firmwares", FlipStoreSubmenuIndexFirmwares, callback_submenu_choices, app);
     submenu_add_item(app->submenu_options, "ESP32 Firmwares", FlipStoreSubmenuIndexFirmwares, callback_submenu_choices, app);
-    //
-    for (int i = 0; i < 3; i++)
-    {
-        submenu_add_item(app->submenu_firmwares, firmwares[i], FlipStoreSubmenuIndexStartFirmwares + i, callback_submenu_choices, app);
-    }
+
     //
     //
     submenu_add_item(app->submenu_app_list, "Bluetooth", FlipStoreSubmenuIndexAppListBluetooth, callback_submenu_choices, app);
     submenu_add_item(app->submenu_app_list, "Bluetooth", FlipStoreSubmenuIndexAppListBluetooth, callback_submenu_choices, app);
     submenu_add_item(app->submenu_app_list, "Games", FlipStoreSubmenuIndexAppListGames, callback_submenu_choices, app);
     submenu_add_item(app->submenu_app_list, "Games", FlipStoreSubmenuIndexAppListGames, callback_submenu_choices, app);

+ 1 - 1
application.fam

@@ -10,5 +10,5 @@ App(
     fap_description="Download apps via WiFi directly to your Flipper Zero",
     fap_description="Download apps via WiFi directly to your Flipper Zero",
     fap_author="JBlanked",
     fap_author="JBlanked",
     fap_weburl="https://github.com/jblanked/FlipStore",
     fap_weburl="https://github.com/jblanked/FlipStore",
-    fap_version="0.5",
+    fap_version="0.6",
 )
 )

+ 15 - 34
apps/flip_store_apps.c

@@ -9,6 +9,21 @@ bool flip_store_saved_data = false;
 bool flip_store_saved_success = false;
 bool flip_store_saved_success = false;
 uint32_t flip_store_category_index = 0;
 uint32_t flip_store_category_index = 0;
 
 
+// define the list of categories
+char *categories[] = {
+    "Bluetooth",
+    "Games",
+    "GPIO",
+    "Infrared",
+    "iButton",
+    "Media",
+    "NFC",
+    "RFID",
+    "Sub-GHz",
+    "Tools",
+    "USB",
+};
+
 FlipStoreAppInfo *flip_catalog_alloc()
 FlipStoreAppInfo *flip_catalog_alloc()
 {
 {
     FlipStoreAppInfo *app_catalog = (FlipStoreAppInfo *)malloc(MAX_APP_COUNT * sizeof(FlipStoreAppInfo));
     FlipStoreAppInfo *app_catalog = (FlipStoreAppInfo *)malloc(MAX_APP_COUNT * sizeof(FlipStoreAppInfo));
@@ -307,40 +322,6 @@ bool flip_store_get_fap_file(char *build_id, uint8_t target, uint16_t api_major,
     return sent_request;
     return sent_request;
 }
 }
 
 
-void flip_store_request_error(Canvas *canvas)
-{
-    if (fhttp.last_response != NULL)
-    {
-        if (strstr(fhttp.last_response, "[ERROR] Not connected to Wifi. Failed to reconnect.") != NULL)
-        {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
-            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-        }
-        else if (strstr(fhttp.last_response, "[ERROR] Failed to connect to Wifi.") != NULL)
-        {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
-            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-        }
-        else
-        {
-            FURI_LOG_E(TAG, "Received an error: %s", fhttp.last_response);
-            canvas_draw_str(canvas, 0, 42, "Unusual error...");
-            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-        }
-    }
-    else
-    {
-        canvas_clear(canvas);
-        canvas_draw_str(canvas, 0, 10, "[ERROR] Unknown error.");
-        canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-        canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-    }
-}
 // function to handle the entire installation process "asynchronously"
 // function to handle the entire installation process "asynchronously"
 bool flip_store_install_app(Canvas *canvas, char *category)
 bool flip_store_install_app(Canvas *canvas, char *category)
 {
 {

+ 3 - 2
apps/flip_store_apps.h

@@ -12,6 +12,9 @@
 #define MAX_APP_DESCRIPTION_LENGTH 100
 #define MAX_APP_DESCRIPTION_LENGTH 100
 #define MAX_APP_VERSION_LENGTH 5
 #define MAX_APP_VERSION_LENGTH 5
 
 
+// define the list of categories
+extern char *categories[];
+
 typedef struct
 typedef struct
 {
 {
     char *app_name;
     char *app_name;
@@ -47,8 +50,6 @@ bool flip_store_process_app_list();
 
 
 bool flip_store_get_fap_file(char *build_id, uint8_t target, uint16_t api_major, uint16_t api_minor);
 bool flip_store_get_fap_file(char *build_id, uint8_t target, uint16_t api_major, uint16_t api_minor);
 
 
-void flip_store_request_error(Canvas *canvas);
-
 // function to handle the entire installation process "asynchronously"
 // function to handle the entire installation process "asynchronously"
 bool flip_store_install_app(Canvas *canvas, char *category);
 bool flip_store_install_app(Canvas *canvas, char *category);
 
 

BIN
assets/01-main-menu.png


BIN
assets/05-browse.png


+ 8 - 4
assets/CHANGELOG.md

@@ -1,17 +1,21 @@
+## v0.6
+- Updated app layout
+- Added an option to download Developer Board firmware (Black Magic, FlipperHTTP, and Marauder)
+
 ## v0.5
 ## v0.5
-- Added app descriptions and versioning.
+- Added app descriptions and versioning
 
 
 ## v0.4
 ## v0.4
 - Added an option to delete apps
 - Added an option to delete apps
-- Edit by Willy-JL
+- Edits by Willy-JL
 
 
 ## v0.3
 ## v0.3
 - Edits by Willy-JL
 - Edits by Willy-JL
 - Improved memory allocation
 - Improved memory allocation
-- Stability Patch
+- Stability patch
 
 
 ## v0.2
 ## v0.2
-- Added categories: Users can now navigate through categories, and when FlipStore installs a selected app, it will download directly to the corresponding category's folder in the apps directory.
+- Added categories: Users can now navigate through categories, and when FlipStore installs a selected app, it downloads directly to the corresponding category folder in the apps directory
 - Improved memory allocation to prevent "Out of Memory" warnings
 - Improved memory allocation to prevent "Out of Memory" warnings
 - Updated installation messages
 - Updated installation messages
 
 

+ 5 - 5
assets/README.md

@@ -4,13 +4,13 @@ Download Flipper Zero apps directly to your Flipper Zero using WiFi. You no long
 ## Features
 ## Features
 - App Catalog
 - App Catalog
 - Install Apps
 - Install Apps
-- Delete Apps (coming soon)
+- Delete Apps 
+- Install Developer Board Flashes
 - Install Custom Apps (coming soon)
 - Install Custom Apps (coming soon)
-- Install Devboard Flashes (coming soon)
 - Install Official Firmware (coming soon)
 - Install Official Firmware (coming soon)
 
 
 ## Installation
 ## Installation
-1. Flash your WiFi Devboard: https://github.com/jblanked/FlipperHTTP
+1. Flash your WiFi Dveloper Board or Raspberry Pi Pico W: https://github.com/jblanked/FlipperHTTP
 2. Install the app.
 2. Install the app.
 3. Enjoy :D
 3. Enjoy :D
 
 
@@ -47,9 +47,9 @@ Download Flipper Zero apps directly to your Flipper Zero using WiFi. You no long
 This is a big task, and I welcome all contributors, especially developers interested in animations and graphics. Fork the repository, create a pull request, and I will review your edits.
 This is a big task, and I welcome all contributors, especially developers interested in animations and graphics. Fork the repository, create a pull request, and I will review your edits.
 
 
 ## Known Bugs
 ## Known Bugs
-1. Clicking the catalog results in an "Out of Memory" error.
+1. Clicking a category in the app catalog results in an "Out of Memory" error.
    - This issue has been addressed, but it may still occur. If it does, restart the app.
    - This issue has been addressed, but it may still occur. If it does, restart the app.
 2. The app file is corrupted.
 2. The app file is corrupted.
    - This is likely due to an error parsing the data. Restart the app and wait until the green LED light turns off after downloading the app before exiting the view. If this happens more than three times, the current version of FlipStore may not be able to download that app successfully.
    - This is likely due to an error parsing the data. Restart the app and wait until the green LED light turns off after downloading the app before exiting the view. If this happens more than three times, the current version of FlipStore may not be able to download that app successfully.
-3. The app is frozen on the "Installing" or "Receiving data" screen. 
+3. The app is frozen on the "Installing", "Loading", or "Receiving data" screen. 
    - If it there LED is not on and it's been more than 5 seconds, restart your Flipper Zero with the devboard plugged in.
    - If it there LED is not on and it's been more than 5 seconds, restart your Flipper Zero with the devboard plugged in.

+ 230 - 16
callback/flip_store_callback.c

@@ -1,6 +1,7 @@
 #include <callback/flip_store_callback.h>
 #include <callback/flip_store_callback.h>
 
 
 bool flip_store_app_does_exist = false;
 bool flip_store_app_does_exist = false;
+uint32_t selected_firmware_index = 0;
 
 
 // Callback for drawing the main screen
 // Callback for drawing the main screen
 void flip_store_view_draw_callback_main(Canvas *canvas, void *model)
 void flip_store_view_draw_callback_main(Canvas *canvas, void *model)
@@ -57,6 +58,168 @@ void flip_store_view_draw_callback_main(Canvas *canvas, void *model)
     }
     }
 }
 }
 
 
+// Function to draw the firmware download screen
+void flip_store_view_draw_callback_firmware(Canvas *canvas, void *model)
+{
+    UNUSED(model);
+
+    // Check if the HTTP state is inactive
+    if (fhttp.state == INACTIVE)
+    {
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 0, 7, "Wifi Dev Board disconnected.");
+        canvas_draw_str(canvas, 0, 17, "Please connect to the board.");
+        canvas_draw_str(canvas, 0, 32, "If your board is connected,");
+        canvas_draw_str(canvas, 0, 42, "make sure you have flashed");
+        canvas_draw_str(canvas, 0, 52, "your WiFi Devboard with the");
+        canvas_draw_str(canvas, 0, 62, "latest FlipperHTTP flash.");
+        return;
+    }
+
+    // Set font and clear the canvas for the loading state
+    canvas_set_font(canvas, FontSecondary);
+    canvas_clear(canvas);
+    canvas_draw_str(canvas, 0, 10, "Loading...");
+
+    // Handle first firmware file
+    if (!sent_firmware_request)
+    {
+        sent_firmware_request = true;
+        firmware_request_success = flip_store_get_firmware_file(
+            firmwares[selected_firmware_index].links[0],
+            firmwares[selected_firmware_index].name,
+            strrchr(firmwares[selected_firmware_index].links[0], '/') + 1);
+
+        if (!firmware_request_success)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        return;
+    }
+    else if (sent_firmware_request && !firmware_download_success)
+    {
+        if (!firmware_request_success || fhttp.state == ISSUE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        else if (fhttp.state == RECEIVING)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Downloading file 1...");
+            canvas_draw_str(canvas, 0, 60, "Please wait...");
+        }
+        else if (fhttp.state == IDLE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Success");
+            canvas_draw_str(canvas, 0, 60, "Downloading the next file now.");
+            firmware_download_success = true;
+        }
+        return;
+    }
+
+    // Handle second firmware file
+    if (firmware_download_success && !sent_firmware_request_2)
+    {
+        sent_firmware_request_2 = true;
+        firmware_request_success_2 = flip_store_get_firmware_file(
+            firmwares[selected_firmware_index].links[1],
+            firmwares[selected_firmware_index].name,
+            strrchr(firmwares[selected_firmware_index].links[1], '/') + 1);
+
+        if (!firmware_request_success_2)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        return;
+    }
+    else if (sent_firmware_request_2 && !firmware_download_success_2)
+    {
+        if (!firmware_request_success_2 || fhttp.state == ISSUE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        else if (fhttp.state == RECEIVING)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Downloading file 2...");
+            canvas_draw_str(canvas, 0, 60, "Please wait...");
+        }
+        else if (fhttp.state == IDLE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Success");
+            canvas_draw_str(canvas, 0, 60, "Downloading the next file now.");
+            firmware_download_success_2 = true;
+        }
+        return;
+    }
+
+    // Handle third firmware file
+    if (firmware_download_success && firmware_download_success_2 && !sent_firmware_request_3)
+    {
+        sent_firmware_request_3 = true;
+        firmware_request_success_3 = flip_store_get_firmware_file(
+            firmwares[selected_firmware_index].links[2],
+            firmwares[selected_firmware_index].name,
+            strrchr(firmwares[selected_firmware_index].links[2], '/') + 1);
+
+        if (!firmware_request_success_3)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        return;
+    }
+    else if (sent_firmware_request_3 && !firmware_download_success_3)
+    {
+        if (!firmware_request_success_3 || fhttp.state == ISSUE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            flip_store_request_error(canvas);
+        }
+        else if (fhttp.state == RECEIVING)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Downloading file 3...");
+            canvas_draw_str(canvas, 0, 60, "Please wait...");
+        }
+        else if (fhttp.state == IDLE)
+        {
+            canvas_set_font(canvas, FontSecondary);
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "Success");
+            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+            firmware_download_success_3 = true;
+        }
+        return;
+    }
+
+    // All files downloaded successfully
+    if (firmware_download_success && firmware_download_success_2 && firmware_download_success_3)
+    {
+        canvas_set_font(canvas, FontSecondary);
+        canvas_clear(canvas);
+        canvas_draw_str(canvas, 0, 10, "Files downloaded successfully.");
+        canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+    }
+}
+
 // Function to draw the message on the canvas with word wrapping
 // Function to draw the message on the canvas with word wrapping
 void draw_description(Canvas *canvas, const char *description, int x, int y)
 void draw_description(Canvas *canvas, const char *description, int x, int y)
 {
 {
@@ -263,6 +426,7 @@ uint32_t callback_to_submenu(void *context)
         return VIEW_NONE;
         return VIEW_NONE;
     }
     }
     UNUSED(context);
     UNUSED(context);
+    firmware_free();
     return FlipStoreViewSubmenu;
     return FlipStoreViewSubmenu;
 }
 }
 
 
@@ -274,9 +438,32 @@ uint32_t callback_to_submenu_options(void *context)
         return VIEW_NONE;
         return VIEW_NONE;
     }
     }
     UNUSED(context);
     UNUSED(context);
+    firmware_free();
     return FlipStoreViewSubmenuOptions;
     return FlipStoreViewSubmenuOptions;
 }
 }
 
 
+uint32_t callback_to_firmware_list(void *context)
+{
+    if (!context)
+    {
+        FURI_LOG_E(TAG, "Context is NULL");
+        return VIEW_NONE;
+    }
+    UNUSED(context);
+    sent_firmware_request = false;
+    sent_firmware_request_2 = false;
+    sent_firmware_request_3 = false;
+    //
+    firmware_request_success = false;
+    firmware_request_success_2 = false;
+    firmware_request_success_3 = false;
+    //
+    firmware_download_success = false;
+    firmware_download_success_2 = false;
+    firmware_download_success_3 = false;
+    return FlipStoreViewFirmwares;
+}
+
 uint32_t callback_to_app_list(void *context)
 uint32_t callback_to_app_list(void *context)
 {
 {
     if (!context)
     if (!context)
@@ -290,6 +477,7 @@ uint32_t callback_to_app_list(void *context)
     flip_store_saved_data = false;
     flip_store_saved_data = false;
     flip_store_saved_success = false;
     flip_store_saved_success = false;
     flip_store_app_does_exist = false;
     flip_store_app_does_exist = false;
+    sent_firmware_request = false;
     return FlipStoreViewAppList;
     return FlipStoreViewAppList;
 }
 }
 
 
@@ -315,7 +503,7 @@ void settings_item_selected(void *context, uint32_t index)
     }
     }
 }
 }
 
 
-void dialog_callback(DialogExResult result, void *context)
+void dialog_delete_callback(DialogExResult result, void *context)
 {
 {
     furi_assert(context);
     furi_assert(context);
     FlipStoreApp *app = (FlipStoreApp *)context;
     FlipStoreApp *app = (FlipStoreApp *)context;
@@ -347,6 +535,22 @@ void dialog_callback(DialogExResult result, void *context)
     }
     }
 }
 }
 
 
+void dialog_firmware_callback(DialogExResult result, void *context)
+{
+    furi_assert(context);
+    FlipStoreApp *app = (FlipStoreApp *)context;
+    if (result == DialogExResultLeft) // No
+    {
+        // switch to the firmware list
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
+    }
+    else if (result == DialogExResultRight)
+    {
+        // download the firmware then return to the firmware list
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwareDownload);
+    }
+}
+
 void popup_callback(void *context)
 void popup_callback(void *context)
 {
 {
     FlipStoreApp *app = (FlipStoreApp *)context;
     FlipStoreApp *app = (FlipStoreApp *)context;
@@ -398,6 +602,23 @@ void callback_submenu_choices(void *context, uint32_t index)
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAppList);
         break;
         break;
     case FlipStoreSubmenuIndexFirmwares:
     case FlipStoreSubmenuIndexFirmwares:
+        if (!app->submenu_firmwares)
+        {
+            FURI_LOG_E(TAG, "Submenu firmwares is NULL");
+            return;
+        }
+        firmwares = firmware_alloc();
+        if (firmwares == NULL)
+        {
+            FURI_LOG_E(TAG, "Failed to allocate memory for firmwares");
+            return;
+        }
+        submenu_reset(app->submenu_firmwares);
+        submenu_set_header(app->submenu_firmwares, "ESP32 Firmwares");
+        for (int i = 0; i < FIRMWARE_COUNT; i++)
+        {
+            submenu_add_item(app->submenu_firmwares, firmwares[i].name, FlipStoreSubmenuIndexStartFirmwares + i, callback_submenu_choices, app);
+        }
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
         break;
         break;
     case FlipStoreSubmenuIndexAppListBluetooth:
     case FlipStoreSubmenuIndexAppListBluetooth:
@@ -463,28 +684,21 @@ void callback_submenu_choices(void *context, uint32_t index)
             uint32_t firmware_index = index - FlipStoreSubmenuIndexStartFirmwares;
             uint32_t firmware_index = index - FlipStoreSubmenuIndexStartFirmwares;
 
 
             // Check if the firmware index is valid
             // Check if the firmware index is valid
-            if ((int)firmware_index >= 0 && firmware_index < 3)
+            if ((int)firmware_index >= 0 && firmware_index < FIRMWARE_COUNT)
             {
             {
                 // Get the firmware name
                 // Get the firmware name
-                char *firmware_name = firmwares[firmware_index];
-
-                // Check if the firmware name is valid
-                if (firmware_name != NULL && strlen(firmware_name) > 0)
-                {
-                    // do nothing for now
-                    popup_set_header(app->popup, firmware_name, 0, 0, AlignLeft, AlignTop);
-                    popup_set_text(app->popup, "Not implemented yet :D", 0, 50, AlignLeft, AlignTop);
+                selected_firmware_index = firmware_index;
 
 
-                    view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewPopup);
-                }
-                else
-                {
-                    FURI_LOG_E(TAG, "Invalid firmware name");
-                }
+                // Switch to the firmware download view
+                dialog_ex_set_header(app->dialog_firmware, firmwares[firmware_index].name, 0, 0, AlignLeft, AlignTop);
+                view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwareDialog);
             }
             }
             else
             else
             {
             {
                 FURI_LOG_E(TAG, "Invalid firmware index");
                 FURI_LOG_E(TAG, "Invalid firmware index");
+                popup_set_header(app->popup, "[ERROR]", 0, 0, AlignLeft, AlignTop);
+                popup_set_text(app->popup, "Issue parsing firmwarex", 0, 50, AlignLeft, AlignTop);
+                view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewPopup);
             }
             }
         }
         }
         // Check if the index is within the app list range
         // Check if the index is within the app list range

+ 8 - 1
callback/flip_store_callback.h

@@ -7,15 +7,19 @@
 #include <ctype.h>
 #include <ctype.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <apps/flip_store_apps.h>
 #include <apps/flip_store_apps.h>
+#include <firmwares/flip_store_firmwares.h>
 #include <flip_storage/flip_store_storage.h>
 #include <flip_storage/flip_store_storage.h>
 
 
 #define MAX_LINE_LENGTH 30
 #define MAX_LINE_LENGTH 30
 
 
 extern bool flip_store_app_does_exist;
 extern bool flip_store_app_does_exist;
+extern uint32_t selected_firmware_index;
 
 
 // Callback for drawing the main screen
 // Callback for drawing the main screen
 void flip_store_view_draw_callback_main(Canvas *canvas, void *model);
 void flip_store_view_draw_callback_main(Canvas *canvas, void *model);
 
 
+void flip_store_view_draw_callback_firmware(Canvas *canvas, void *model);
+
 // Function to draw the description on the canvas with word wrapping
 // Function to draw the description on the canvas with word wrapping
 void draw_description(Canvas *canvas, const char *user_message, int x, int y);
 void draw_description(Canvas *canvas, const char *user_message, int x, int y);
 
 
@@ -31,11 +35,14 @@ uint32_t callback_to_submenu(void *context);
 
 
 uint32_t callback_to_submenu_options(void *context);
 uint32_t callback_to_submenu_options(void *context);
 
 
+uint32_t callback_to_firmware_list(void *context);
+
 uint32_t callback_to_app_list(void *context);
 uint32_t callback_to_app_list(void *context);
 
 
 void settings_item_selected(void *context, uint32_t index);
 void settings_item_selected(void *context, uint32_t index);
 
 
-void dialog_callback(DialogExResult result, void *context);
+void dialog_delete_callback(DialogExResult result, void *context);
+void dialog_firmware_callback(DialogExResult result, void *context);
 
 
 void popup_callback(void *context);
 void popup_callback(void *context);
 
 

+ 113 - 0
firmwares/flip_store_firmwares.c

@@ -0,0 +1,113 @@
+#include <firmwares/flip_store_firmwares.h>
+
+Firmware *firmwares = NULL;
+bool sent_firmware_request = false;
+bool sent_firmware_request_2 = false;
+bool sent_firmware_request_3 = false;
+//
+bool firmware_request_success = false;
+bool firmware_request_success_2 = false;
+bool firmware_request_success_3 = false;
+//
+bool firmware_download_success = false;
+bool firmware_download_success_2 = false;
+bool firmware_download_success_3 = false;
+
+Firmware *firmware_alloc()
+{
+    Firmware *fw = (Firmware *)malloc(FIRMWARE_COUNT * sizeof(Firmware));
+    if (!fw)
+    {
+        FURI_LOG_E(TAG, "Failed to allocate memory for Firmware");
+        return NULL;
+    }
+    for (int i = 0; i < FIRMWARE_COUNT; i++)
+    {
+        if (fw[i].name == NULL)
+        {
+            fw[i].name = (char *)malloc(16);
+            if (!fw[i].name)
+            {
+                FURI_LOG_E(TAG, "Failed to allocate memory for Firmware name");
+                return NULL;
+            }
+        }
+        for (int j = 0; j < FIRMWARE_LINKS; j++)
+        {
+            if (fw[i].links[j] == NULL)
+            {
+                fw[i].links[j] = (char *)malloc(256);
+                if (!fw[i].links[j])
+                {
+                    FURI_LOG_E(TAG, "Failed to allocate memory for Firmware links");
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    // Black Magic
+    fw[0].name = "Black Magic";
+    fw[0].links[0] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/STATIC/BM/bootloader.bin";
+    fw[0].links[1] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/STATIC/BM/partition-table.bin";
+    fw[0].links[2] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/STATIC/BM/blackmagic.bin";
+
+    // FlipperHTTP
+    fw[1].name = "FlipperHTTP";
+    fw[1].links[0] = "https://raw.githubusercontent.com/jblanked/FlipperHTTP/main/flipper_http_bootloader.bin";
+    fw[1].links[1] = "https://raw.githubusercontent.com/jblanked/FlipperHTTP/main/flipper_http_firmware_a.bin";
+    fw[1].links[2] = "https://raw.githubusercontent.com/jblanked/FlipperHTTP/main/flipper_http_partitions.bin";
+
+    // Marauder
+    fw[2].name = "Marauder";
+    fw[2].links[0] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/STATIC/M/FLIPDEV/esp32_marauder.ino.bootloader.bin";
+    fw[2].links[1] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/STATIC/M/FLIPDEV/esp32_marauder.ino.partitions.bin";
+    fw[2].links[2] = "https://raw.githubusercontent.com/FZEEFlasher/fzeeflasher.github.io/main/resources/CURRENT/esp32_marauder_v1_0_0_20240626_flipper.bin";
+
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/STATIC/BM/bootloader.bin
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/STATIC/BM/partition-table.bin
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/STATIC/BM/blackmagic.bin
+
+    // https://api.github.com/repos/jblanked/FlipperHTTP/contents/flipper_http_bootloader.bin
+    // https://api.github.com/repos/jblanked/FlipperHTTP/contents/flipper_http_firmware_a.bin
+    // https://api.github.com/repos/jblanked/FlipperHTTP/contents/flipper_http_partitions.bin
+
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/STATIC/M/FLIPDEV/esp32_marauder.ino.bootloader.bin
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/STATIC/M/FLIPDEV/esp32_marauder.ino.partitions.bin
+    // https://api.github.com/repos/FZEEFlasher/fzeeflasher.github.io/contents/resources/CURRENT/esp32_marauder_v1_0_0_20240626_flipper.bin
+    return fw;
+}
+void firmware_free()
+{
+    if (firmwares)
+    {
+        free(firmwares);
+    }
+}
+
+bool flip_store_get_firmware_file(char *link, char *name, char *filename)
+{
+    if (fhttp.state == INACTIVE)
+    {
+        return false;
+    }
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    char directory_path[64];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/esp_flasher");
+    storage_common_mkdir(storage, directory_path);
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/esp_flasher/%s", firmwares[selected_firmware_index].name);
+    storage_common_mkdir(storage, directory_path);
+    snprintf(fhttp.file_path, sizeof(fhttp.file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/esp_flasher/%s/%s", name, filename);
+    fhttp.save_received_data = false;
+    fhttp.is_bytes_request = true;
+    char *headers = jsmn("Content-Type", "application/octet-stream");
+    bool sent_request = flipper_http_get_request_bytes(link, headers);
+    free(headers);
+    if (sent_request)
+    {
+        fhttp.state = RECEIVING;
+        return true;
+    }
+    fhttp.state = ISSUE;
+    return false;
+}

+ 31 - 0
firmwares/flip_store_firmwares.h

@@ -0,0 +1,31 @@
+#ifndef FLIP_STORE_FIRMWARES_H
+#define FLIP_STORE_FIRMWARES_H
+
+#include <flip_store.h>
+#include <flip_storage/flip_store_storage.h>
+#include <callback/flip_store_callback.h>
+
+typedef struct
+{
+    char *name;
+    char *links[FIRMWARE_LINKS];
+} Firmware;
+
+extern Firmware *firmwares;
+Firmware *firmware_alloc();
+void firmware_free();
+
+// download and waiting process
+bool flip_store_get_firmware_file(char *link, char *name, char *filename);
+
+extern bool sent_firmware_request;
+extern bool sent_firmware_request_2;
+extern bool sent_firmware_request_3;
+extern bool firmware_request_success;
+extern bool firmware_request_success_2;
+extern bool firmware_request_success_3;
+extern bool firmware_download_success;
+extern bool firmware_download_success_2;
+extern bool firmware_download_success_3;
+
+#endif // FLIP_STORE_FIRMWARES_H

+ 45 - 21
flip_store.c

@@ -1,26 +1,5 @@
 #include <flip_store.h>
 #include <flip_store.h>
 
 
-// define the list of categories
-char *categories[] = {
-    "Bluetooth",
-    "Games",
-    "GPIO",
-    "Infrared",
-    "iButton",
-    "Media",
-    "NFC",
-    "RFID",
-    "Sub-GHz",
-    "Tools",
-    "USB",
-};
-
-char *firmwares[] = {
-    "Black Magic",
-    "FlipperHTTP",
-    "Marauder",
-};
-
 // Function to free the resources used by FlipStoreApp
 // Function to free the resources used by FlipStoreApp
 void flip_store_app_free(FlipStoreApp *app)
 void flip_store_app_free(FlipStoreApp *app)
 {
 {
@@ -41,6 +20,11 @@ void flip_store_app_free(FlipStoreApp *app)
         view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppInfo);
         view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppInfo);
         view_free(app->view_app_info);
         view_free(app->view_app_info);
     }
     }
+    if (app->view_firmware_download)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewFirmwareDownload);
+        view_free(app->view_firmware_download);
+    }
 
 
     // Free Submenu(s)
     // Free Submenu(s)
     if (app->submenu_main)
     if (app->submenu_main)
@@ -158,6 +142,11 @@ void flip_store_app_free(FlipStoreApp *app)
         view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppDelete);
         view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppDelete);
         dialog_ex_free(app->dialog_delete);
         dialog_ex_free(app->dialog_delete);
     }
     }
+    if (app->dialog_firmware)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewFirmwareDialog);
+        dialog_ex_free(app->dialog_firmware);
+    }
 
 
     // deinitalize flipper http
     // deinitalize flipper http
     flipper_http_deinit();
     flipper_http_deinit();
@@ -171,3 +160,38 @@ void flip_store_app_free(FlipStoreApp *app)
     // free the app
     // free the app
     free(app);
     free(app);
 }
 }
+
+void flip_store_request_error(Canvas *canvas)
+{
+    if (fhttp.last_response != NULL)
+    {
+        if (strstr(fhttp.last_response, "[ERROR] Not connected to Wifi. Failed to reconnect.") != NULL)
+        {
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
+            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
+            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+        }
+        else if (strstr(fhttp.last_response, "[ERROR] Failed to connect to Wifi.") != NULL)
+        {
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
+            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
+            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+        }
+        else
+        {
+            FURI_LOG_E(TAG, "Received an error: %s", fhttp.last_response);
+            canvas_draw_str(canvas, 0, 42, "Unusual error...");
+            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
+            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+        }
+    }
+    else
+    {
+        canvas_clear(canvas);
+        canvas_draw_str(canvas, 0, 10, "[ERROR] Unknown error.");
+        canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
+        canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+    }
+}

+ 14 - 8
flip_store.h

@@ -14,10 +14,8 @@
 #include <jsmn/jsmn.h>
 #include <jsmn/jsmn.h>
 #include <flip_store_icons.h>
 #include <flip_store_icons.h>
 #define TAG "FlipStore"
 #define TAG "FlipStore"
-
-// define the list of categories
-extern char *categories[];
-extern char *firmwares[];
+#define FIRMWARE_COUNT 3
+#define FIRMWARE_LINKS 3
 
 
 // Define the submenu items for our FlipStore application
 // Define the submenu items for our FlipStore application
 typedef enum
 typedef enum
@@ -51,7 +49,7 @@ typedef enum
 // Define a single view for our FlipStore application
 // Define a single view for our FlipStore application
 typedef enum
 typedef enum
 {
 {
-    FlipStoreViewMain, // The main screen
+    FlipStoreViewMain, // The main screen for downloading apps
     //
     //
     FlipStoreViewSubmenu,        // The submenu
     FlipStoreViewSubmenu,        // The submenu
     FlipStoreViewSubmenuOptions, // The submenu options
     FlipStoreViewSubmenuOptions, // The submenu options
@@ -63,8 +61,10 @@ typedef enum
     //
     //
     FlipStoreViewPopup, // The popup screen
     FlipStoreViewPopup, // The popup screen
     //
     //
-    FlipStoreViewAppList,   // The app list screen
-    FlipStoreViewFirmwares, // The firmwares screen
+    FlipStoreViewAppList,          // The app list screen
+    FlipStoreViewFirmwares,        // The firmwares screen (submenu)
+    FlipStoreViewFirmwareDialog,   // The firmware view (DialogEx) of the selected firmware
+    FlipStoreViewFirmwareDownload, // The firmware download screen
     //
     //
     FlipStoreViewAppInfo,     // The app info screen (widget) of the selected app
     FlipStoreViewAppInfo,     // The app info screen (widget) of the selected app
     FlipStoreViewAppDownload, // The app download screen (widget) of the selected app
     FlipStoreViewAppDownload, // The app download screen (widget) of the selected app
@@ -89,7 +89,11 @@ typedef struct
     ViewDispatcher *view_dispatcher; // Switches between our views
     ViewDispatcher *view_dispatcher; // Switches between our views
     View *view_main;                 // The main screen for downloading apps
     View *view_main;                 // The main screen for downloading apps
     View *view_app_info;             // The app info screen (view) of the selected app
     View *view_app_info;             // The app info screen (view) of the selected app
-    Submenu *submenu_main;           // The submenu (main)
+    //
+    DialogEx *dialog_firmware;    // The dialog for installing a firmware
+    View *view_firmware_download; // The firmware download screen (view) of the selected firmware
+    //
+    Submenu *submenu_main; // The submenu (main)
     //
     //
     Submenu *submenu_options;   // The submenu (options)
     Submenu *submenu_options;   // The submenu (options)
     Submenu *submenu_app_list;  // The submenu (app list) for the selected category
     Submenu *submenu_app_list;  // The submenu (app list) for the selected category
@@ -127,4 +131,6 @@ typedef struct
 
 
 void flip_store_app_free(FlipStoreApp *app);
 void flip_store_app_free(FlipStoreApp *app);
 
 
+void flip_store_request_error(Canvas *canvas);
+
 #endif // FLIP_STORE_E_H
 #endif // FLIP_STORE_E_H

+ 1 - 1
flipper_http/flipper_http.h

@@ -18,7 +18,7 @@
 #define RX_BUF_SIZE 2048                  // UART RX buffer size
 #define RX_BUF_SIZE 2048                  // UART RX buffer size
 #define RX_LINE_BUFFER_SIZE 8192          // UART RX line buffer size (increase for large responses)
 #define RX_LINE_BUFFER_SIZE 8192          // UART RX line buffer size (increase for large responses)
 #define MAX_FILE_SHOW 8192                // Maximum data from file to show
 #define MAX_FILE_SHOW 8192                // Maximum data from file to show
-#define FILE_BUFFER_SIZE 512              // File buffer size
+#define FILE_BUFFER_SIZE 1024             // File buffer size
 
 
 // Forward declaration for callback
 // Forward declaration for callback
 typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
 typedef void (*FlipperHTTP_Callback)(const char *line, void *context);