Просмотр исходного кода

FlipStore v0.7.1

- Improved memory allocation
- Fixed a crash when re-entering the same app list
jblanked 1 год назад
Родитель
Сommit
f444161205

+ 1 - 18
alloc/flip_store_alloc.c

@@ -6,12 +6,6 @@ FlipStoreApp *flip_store_app_alloc()
 
     Gui *gui = furi_record_open(RECORD_GUI);
 
-    if (!flipper_http_init(flipper_http_rx_callback, app))
-    {
-        FURI_LOG_E(TAG, "Failed to initialize flipper http");
-        return NULL;
-    }
-
     // Allocate the text input buffer
     app->uart_text_input_buffer_size_ssid = 64;
     app->uart_text_input_buffer_size_pass = 64;
@@ -55,17 +49,6 @@ FlipStoreApp *flip_store_app_alloc()
         return NULL;
     }
 
-    // Widget
-    if (!easy_flipper_set_widget(
-            &app->widget,
-            FlipStoreViewAbout,
-            "Welcome to the FlipStore!\n------\nDownload apps via WiFi and\nrun them on your Flipper!\n------\nwww.github.com/jblanked",
-            callback_to_submenu,
-            &app->view_dispatcher))
-    {
-        return NULL;
-    }
-
     // Popup
     if (!easy_flipper_set_popup(&app->popup, FlipStoreViewPopup, "Failed", 0, 0, "You are not connected to Wifi.\n\nIf you have the FlipperHTTP\nflash installed, then update\nyour WiFi credentials.", 0, 10, popup_callback, callback_to_submenu, &app->view_dispatcher, app))
     {
@@ -132,7 +115,7 @@ FlipStoreApp *flip_store_app_alloc()
     app->variable_item_pass = variable_item_list_add(app->variable_item_list, "Password", 0, NULL, NULL);
 
     // Submenu
-    if (!easy_flipper_set_submenu(&app->submenu_main, FlipStoreViewSubmenu, "FlipStore v0.7", callback_exit_app, &app->view_dispatcher))
+    if (!easy_flipper_set_submenu(&app->submenu_main, FlipStoreViewSubmenu, "FlipStore v0.7.1", callback_exit_app, &app->view_dispatcher))
     {
         return NULL;
     }

+ 25 - 5
app.c

@@ -1,6 +1,5 @@
 #include <flip_store.h>
 #include <alloc/flip_store_alloc.h>
-#include <apps/flip_store_apps.h>
 
 // Entry point for the Hello World application
 int32_t main_flip_store(void *p)
@@ -16,10 +15,32 @@ int32_t main_flip_store(void *p)
         return -1;
     }
 
-    if (!flipper_http_ping())
+    // check if board is connected (Derek Jamison)
+    // initialize the http
+    if (flipper_http_init(flipper_http_rx_callback, app_instance))
     {
-        FURI_LOG_E(TAG, "Failed to ping the device");
-        return -1;
+        if (!flipper_http_ping())
+        {
+            FURI_LOG_E(TAG, "Failed to ping the device");
+            return -1;
+        }
+
+        // Try to wait for pong response.
+        uint8_t counter = 10;
+        while (fhttp.state == INACTIVE && --counter > 0)
+        {
+            FURI_LOG_D(TAG, "Waiting for PONG");
+            furi_delay_ms(100);
+        }
+
+        if (counter == 0)
+            easy_flipper_dialog("FlipperHTTP Error", "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.");
+
+        flipper_http_deinit();
+    }
+    else
+    {
+        easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
     }
 
     // Run the view dispatcher
@@ -27,7 +48,6 @@ int32_t main_flip_store(void *p)
 
     // Free the resources used by the Hello World application
     flip_store_app_free(app_instance);
-    flip_catalog_free();
 
     // Return 0 to indicate success
     return 0;

+ 1 - 1
application.fam

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

+ 16 - 4
apps/flip_store_apps.c

@@ -92,6 +92,9 @@ bool flip_store_process_app_list()
         return false;
     }
 
+    // free the resources
+    flipper_http_deinit();
+
     char *data_cstr = (char *)furi_string_get_cstr(feed_data);
     if (data_cstr == NULL)
     {
@@ -289,14 +292,23 @@ 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)
 {
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
+        return false;
+    }
+    // initialize the http
+    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    {
+        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP.");
+        return false;
+    }
+    fhttp.state = IDLE;
     char url[128];
     fhttp.save_received_data = false;
     fhttp.is_bytes_request = true;
     snprintf(url, sizeof(url), "https://catalog.flipperzero.one/api/v0/application/version/%s/build/compatible?target=f%d&api=%d.%d", build_id, target, api_major, api_minor);
-    char *headers = jsmn("Content-Type", "application/octet-stream");
-    bool sent_request = flipper_http_get_request_bytes(url, headers);
-    free(headers);
-    return sent_request;
+    return flipper_http_get_request_bytes(url, "{\"Content-Type\": \"application/octet-stream\"}");
 }
 
 bool flip_store_install_app(char *category)

+ 4 - 0
assets/CHANGELOG.md

@@ -1,3 +1,7 @@
+## v0.7.1
+- Improved memory allocation
+- Fixed a crash when re-entering the same app list  
+
 ## v0.7
 - Improved memory allocation
 - Added updates from Derek Jamison

+ 121 - 69
callback/flip_store_callback.c

@@ -25,6 +25,8 @@ static char *flip_store_dl_app_parse(DataLoaderModel *model)
     {
         return NULL;
     }
+    // free the resources
+    flipper_http_deinit();
     return "App installed successfully.";
 }
 static void flip_store_dl_app_switch_to_view(FlipStoreApp *app)
@@ -35,6 +37,18 @@ static void flip_store_dl_app_switch_to_view(FlipStoreApp *app)
 static bool flip_store_fetch_app_list(DataLoaderModel *model)
 {
     UNUSED(model);
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
+        return false;
+    }
+    // initialize the http
+    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    {
+        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP.");
+        return false;
+    }
+    fhttp.state = IDLE;
     flip_catalog_free();
     snprintf(
         fhttp.file_path,
@@ -44,75 +58,19 @@ static bool flip_store_fetch_app_list(DataLoaderModel *model)
     fhttp.is_bytes_request = false;
     char url[128];
     snprintf(url, sizeof(url), "https://www.flipsocial.net/api/flipper/apps/%s/max/", categories[flip_store_category_index]);
-    return fhttp.state != INACTIVE && flipper_http_get_request_with_headers(url, "{\"Content-Type\":\"application/json\"}");
+    return flipper_http_get_request_with_headers(url, "{\"Content-Type\":\"application/json\"}");
 }
-static char *flip_store_parse_app_list(DataLoaderModel *model)
+static bool set_appropriate_list(Submenu **submenu)
 {
-    UNUSED(model);
-    if (!app_instance)
-    {
-        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
-        return "Failed to fetch app list.";
-    }
-    Submenu **submenu = NULL;
-    uint32_t view_id = 0;
-    switch (flip_store_category_index)
-    {
-    case 0:
-        submenu = &app_instance->submenu_app_list_bluetooth;
-        view_id = FlipStoreViewAppListBluetooth;
-        break;
-    case 1:
-        submenu = &app_instance->submenu_app_list_games;
-        view_id = FlipStoreViewAppListGames;
-        break;
-    case 2:
-        submenu = &app_instance->submenu_app_list_gpio;
-        view_id = FlipStoreViewAppListGPIO;
-        break;
-    case 3:
-        submenu = &app_instance->submenu_app_list_infrared;
-        view_id = FlipStoreViewAppListInfrared;
-        break;
-    case 4:
-        submenu = &app_instance->submenu_app_list_ibutton;
-        view_id = FlipStoreViewAppListiButton;
-        break;
-    case 5:
-        submenu = &app_instance->submenu_app_list_media;
-        view_id = FlipStoreViewAppListMedia;
-        break;
-    case 6:
-        submenu = &app_instance->submenu_app_list_nfc;
-        view_id = FlipStoreViewAppListNFC;
-        break;
-    case 7:
-        submenu = &app_instance->submenu_app_list_rfid;
-        view_id = FlipStoreViewAppListRFID;
-        break;
-    case 8:
-        submenu = &app_instance->submenu_app_list_subghz;
-        view_id = FlipStoreViewAppListSubGHz;
-        break;
-    case 9:
-        submenu = &app_instance->submenu_app_list_tools;
-        view_id = FlipStoreViewAppListTools;
-        break;
-    case 10:
-        submenu = &app_instance->submenu_app_list_usb;
-        view_id = FlipStoreViewAppListUSB;
-        break;
-    }
     if (!submenu)
     {
         FURI_LOG_E(TAG, "Submenu is NULL");
-        return "Failed to fetch app list.";
+        return false;
     }
-    if (!easy_flipper_set_submenu(submenu, view_id, categories[flip_store_category_index], callback_to_app_list, &app_instance->view_dispatcher))
+    if (!easy_flipper_set_submenu(submenu, FlipStoreViewAppListCategory, categories[flip_store_category_index], callback_to_app_list, &app_instance->view_dispatcher))
     {
-        return NULL;
+        return false;
     }
-
     if (flip_store_process_app_list() && submenu && flip_catalog)
     {
         submenu_reset(*submenu);
@@ -128,14 +86,25 @@ static char *flip_store_parse_app_list(DataLoaderModel *model)
                 break;
             }
         }
-        view_dispatcher_switch_to_view(app_instance->view_dispatcher, view_id);
-        return "Fetched app list successfully.";
+        view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipStoreViewAppListCategory);
+        return true;
     }
     else
     {
         FURI_LOG_E(TAG, "Failed to process the app list");
+        return false;
+    }
+    return false;
+}
+static char *flip_store_parse_app_list(DataLoaderModel *model)
+{
+    UNUSED(model);
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
         return "Failed to fetch app list.";
     }
+    return set_appropriate_list(&app_instance->submenu_app_list_category) ? "App list fetched successfully." : "Failed to fetch app list.";
 }
 static void flip_store_switch_to_app_list(FlipStoreApp *app)
 {
@@ -144,6 +113,18 @@ static void flip_store_switch_to_app_list(FlipStoreApp *app)
 //
 static bool flip_store_fetch_firmware(DataLoaderModel *model)
 {
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
+        return false;
+    }
+    // initialize the http
+    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    {
+        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP.");
+        return false;
+    }
+    fhttp.state = IDLE;
     if (model->request_index == 0)
     {
         firmware_free();
@@ -178,6 +159,8 @@ static bool flip_store_fetch_firmware(DataLoaderModel *model)
 }
 static char *flip_store_parse_firmware(DataLoaderModel *model)
 {
+    // free the resources
+    flipper_http_deinit();
     if (model->request_index == 0)
     {
         if (firmware_request_success)
@@ -547,16 +530,62 @@ void popup_callback(void *context)
     }
     view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewSubmenu);
 }
+static bool alloc_about_view(FlipStoreApp *app)
+{
+    if (!app)
+    {
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
+        return false;
+    }
+    if (!app->widget)
+    {
+        if (!easy_flipper_set_widget(
+                &app->widget,
+                FlipStoreViewAbout,
+                "Welcome to the FlipStore!\n------\nDownload apps via WiFi and\nrun them on your Flipper!\n------\nwww.github.com/jblanked",
+                callback_to_submenu,
+                &app->view_dispatcher))
+        {
+            return false;
+        }
+        if (!app->widget)
+        {
+            return false;
+        }
+    }
+    return true;
+}
 
-uint32_t callback_exit_app(void *context)
+static void free_about_view()
 {
-    // Exit the application
-    if (!context)
+    if (!app_instance)
     {
-        FURI_LOG_E(TAG, "Context is NULL");
-        return VIEW_NONE;
+        FURI_LOG_E(TAG, "FlipStoreApp is NULL");
+        return;
+    }
+    if (app_instance->widget != NULL)
+    {
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipStoreViewAbout);
+        widget_free(app_instance->widget);
+        app_instance->widget = NULL;
+    }
+}
+static void free_all_views()
+{
+    free_about_view();
+    // clear app list views
+    if (app_instance->submenu_app_list_category)
+    {
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipStoreViewAppListCategory);
+        submenu_free(app_instance->submenu_app_list_category);
+        app_instance->submenu_app_list_category = NULL;
     }
+}
+
+uint32_t callback_exit_app(void *context)
+{
     UNUSED(context);
+    free_all_views();
     return VIEW_NONE; // Return VIEW_NONE to exit the app
 }
 
@@ -568,9 +597,16 @@ void callback_submenu_choices(void *context, uint32_t index)
         FURI_LOG_E(TAG, "FlipStoreApp is NULL");
         return;
     }
+
     switch (index)
     {
     case FlipStoreSubmenuIndexAbout:
+        free_all_views();
+        if (!alloc_about_view(app))
+        {
+            FURI_LOG_E(TAG, "Failed to set about view");
+            return;
+        }
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewAbout);
         break;
     case FlipStoreSubmenuIndexSettings:
@@ -605,56 +641,67 @@ void callback_submenu_choices(void *context, uint32_t index)
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipStoreViewFirmwares);
         break;
     case FlipStoreSubmenuIndexAppListBluetooth:
+        free_all_views();
         flip_store_category_index = 0;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListGames:
+        free_all_views();
         flip_store_category_index = 1;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListGPIO:
+        free_all_views();
         flip_store_category_index = 2;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListInfrared:
+        free_all_views();
         flip_store_category_index = 3;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListiButton:
+        free_all_views();
         flip_store_category_index = 4;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListMedia:
+        free_all_views();
         flip_store_category_index = 5;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListNFC:
+        free_all_views();
         flip_store_category_index = 6;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListRFID:
+        free_all_views();
         flip_store_category_index = 7;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListSubGHz:
+        free_all_views();
         flip_store_category_index = 8;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListTools:
+        free_all_views();
         flip_store_category_index = 9;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
         break;
     case FlipStoreSubmenuIndexAppListUSB:
+        free_all_views();
         flip_store_category_index = 10;
         flip_store_app_does_exist = false;
         flip_store_switch_to_app_list(app);
@@ -920,7 +967,12 @@ static void flip_store_loader_process_callback(void *context)
                 }
 
                 // Clear any previous responses
-                strncpy(fhttp.last_response, "", 1);
+                if (fhttp.last_response != NULL)
+                {
+                    free(fhttp.last_response);
+                    fhttp.last_response = NULL;
+                }
+                // strncpy(fhttp.last_response, "", 1);
                 bool request_status = fetch(model);
                 if (!request_status)
                 {

+ 20 - 0
easy_flipper/easy_flipper.c

@@ -1,5 +1,25 @@
 #include <easy_flipper/easy_flipper.h>
 
+void easy_flipper_dialog(
+    char *header,
+    char *text)
+{
+    DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS);
+    DialogMessage *message = dialog_message_alloc();
+    dialog_message_set_header(
+        message, header, 64, 0, AlignCenter, AlignTop);
+    dialog_message_set_text(
+        message,
+        text,
+        0,
+        63,
+        AlignLeft,
+        AlignBottom);
+    dialog_message_show(dialogs, message);
+    dialog_message_free(message);
+    furi_record_close(RECORD_DIALOGS);
+}
+
 /**
  * @brief Navigation callback for exiting the application
  * @param context The context - unused

+ 7 - 0
easy_flipper/easy_flipper.h

@@ -8,6 +8,7 @@
 #include <gui/view.h>
 #include <gui/modules/submenu.h>
 #include <gui/view_dispatcher.h>
+#include <gui/elements.h>
 #include <gui/modules/menu.h>
 #include <gui/modules/submenu.h>
 #include <gui/modules/widget.h>
@@ -15,6 +16,8 @@
 #include <gui/modules/text_box.h>
 #include <gui/modules/variable_item_list.h>
 #include <gui/modules/dialog_ex.h>
+#include <notification/notification.h>
+#include <dialogs/dialogs.h>
 #include <gui/modules/popup.h>
 #include <gui/modules/loading.h>
 #include <text_input/uart_text_input.h>
@@ -24,6 +27,10 @@
 
 #define EASY_TAG "EasyFlipper"
 
+void easy_flipper_dialog(
+    char *header,
+    char *text);
+
 /**
  * @brief Navigation callback for exiting the application
  * @param context The context - unused

+ 1 - 3
firmwares/flip_store_firmwares.c

@@ -100,9 +100,7 @@ bool flip_store_get_firmware_file(char *link, char *name, char *filename)
     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);
+    bool sent_request = flipper_http_get_request_bytes(link, "{\"Content-Type\":\"application/octet-stream\"}");
     if (sent_request)
     {
         fhttp.state = RECEIVING;

+ 3 - 66
flip_store.c

@@ -1,6 +1,6 @@
 #include <flip_store.h>
+#include <apps/flip_store_apps.h>
 
-void flip_store_loader_free_model(View *view);
 FlipStoreApp *app_instance = NULL;
 
 // Function to free the resources used by FlipStoreApp
@@ -12,6 +12,8 @@ void flip_store_app_free(FlipStoreApp *app)
         return;
     }
 
+    flip_catalog_free();
+
     // Free Widget(s)
     if (app->widget_result)
     {
@@ -54,68 +56,6 @@ void flip_store_app_free(FlipStoreApp *app)
         view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewFirmwares);
         submenu_free(app->submenu_firmwares);
     }
-    if (app->submenu_app_list_bluetooth)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListBluetooth);
-        submenu_free(app->submenu_app_list_bluetooth);
-    }
-    if (app->submenu_app_list_games)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListGames);
-        submenu_free(app->submenu_app_list_games);
-    }
-    if (app->submenu_app_list_gpio)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListGPIO);
-        submenu_free(app->submenu_app_list_gpio);
-    }
-    if (app->submenu_app_list_infrared)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListInfrared);
-        submenu_free(app->submenu_app_list_infrared);
-    }
-    if (app->submenu_app_list_ibutton)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListiButton);
-        submenu_free(app->submenu_app_list_ibutton);
-    }
-    if (app->submenu_app_list_media)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListMedia);
-        submenu_free(app->submenu_app_list_media);
-    }
-    if (app->submenu_app_list_nfc)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListNFC);
-        submenu_free(app->submenu_app_list_nfc);
-    }
-    if (app->submenu_app_list_rfid)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListRFID);
-        submenu_free(app->submenu_app_list_rfid);
-    }
-    if (app->submenu_app_list_subghz)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListSubGHz);
-        submenu_free(app->submenu_app_list_subghz);
-    }
-    if (app->submenu_app_list_tools)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListTools);
-        submenu_free(app->submenu_app_list_tools);
-    }
-    if (app->submenu_app_list_usb)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAppListUSB);
-        submenu_free(app->submenu_app_list_usb);
-    }
-
-    // Free Widget(s)
-    if (app->widget)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipStoreViewAbout);
-        widget_free(app->widget);
-    }
 
     // Free Variable Item List(s)
     if (app->variable_item_list)
@@ -155,9 +95,6 @@ void flip_store_app_free(FlipStoreApp *app)
         dialog_ex_free(app->dialog_firmware);
     }
 
-    // deinitalize flipper http
-    flipper_http_deinit();
-
     // free the view dispatcher
     view_dispatcher_free(app->view_dispatcher);
 

+ 27 - 49
flip_store.h

@@ -50,39 +50,29 @@ typedef enum
 typedef enum
 {
     //
-    FlipStoreViewSubmenu,          // The submenu
-    FlipStoreViewSubmenuOptions,   // The submenu options
-                                   //
-    FlipStoreViewAbout,            // The about screen
-    FlipStoreViewSettings,         // The settings screen
-    FlipStoreViewTextInputSSID,    // The text input screen for SSID
-    FlipStoreViewTextInputPass,    // The text input screen for password
-                                   //
-    FlipStoreViewPopup,            // The popup screen
-                                   //
-    FlipStoreViewAppList,          // The app list screen
-    FlipStoreViewFirmwares,        // The firmwares screen (submenu)
-    FlipStoreViewFirmwareDialog,   // The firmware view (DialogEx) of the selected firmware
-                                   //
-    FlipStoreViewAppInfo,          // The app info screen (widget) of the selected app
-    FlipStoreViewAppDownload,      // The app download screen (widget) of the selected app
-    FlipStoreViewAppDelete,        // The app delete screen (DialogEx) of the selected app
-                                   //
-    FlipStoreViewAppListBluetooth, // the app list screen for Bluetooth
-    FlipStoreViewAppListGames,     // the app list screen for Games
-    FlipStoreViewAppListGPIO,      // the app list screen for GPIO
-    FlipStoreViewAppListInfrared,  // the app list screen for Infrared
-    FlipStoreViewAppListiButton,   // the app list screen for iButton
-    FlipStoreViewAppListMedia,     // the app list screen for Media
-    FlipStoreViewAppListNFC,       // the app list screen for NFC
-    FlipStoreViewAppListRFID,      // the app list screen for RFID
-    FlipStoreViewAppListSubGHz,    // the app list screen for Sub-GHz
-    FlipStoreViewAppListTools,     // the app list screen for Tools
-    FlipStoreViewAppListUSB,       // the app list screen for USB
-                                   //
-                                   //
-    FlipStoreViewWidgetResult,     // The text box that displays the random fact
-    FlipStoreViewLoader,           // The loader screen retrieves data from the internet
+    FlipStoreViewSubmenu,         // The submenu
+    FlipStoreViewSubmenuOptions,  // The submenu options
+                                  //
+    FlipStoreViewAbout,           // The about screen
+    FlipStoreViewSettings,        // The settings screen
+    FlipStoreViewTextInputSSID,   // The text input screen for SSID
+    FlipStoreViewTextInputPass,   // The text input screen for password
+                                  //
+    FlipStoreViewPopup,           // The popup screen
+                                  //
+    FlipStoreViewAppList,         // The app list screen
+    FlipStoreViewFirmwares,       // The firmwares screen (submenu)
+    FlipStoreViewFirmwareDialog,  // The firmware view (DialogEx) of the selected firmware
+                                  //
+    FlipStoreViewAppInfo,         // The app info screen (widget) of the selected app
+    FlipStoreViewAppDownload,     // The app download screen (widget) of the selected app
+    FlipStoreViewAppDelete,       // The app delete screen (DialogEx) of the selected app
+                                  //
+    FlipStoreViewAppListCategory, // the app list screen for each category
+                                  //
+                                  //
+    FlipStoreViewWidgetResult,    // The text box that displays the random fact
+    FlipStoreViewLoader,          // The loader screen retrieves data from the internet
 } FlipStoreView;
 
 // Each screen will have its own view
@@ -99,22 +89,10 @@ typedef struct
     //
     Submenu *submenu_main; // The submenu (main)
     //
-    Submenu *submenu_options;   // The submenu (options)
-    Submenu *submenu_app_list;  // The submenu (app list) for the selected category
-    Submenu *submenu_firmwares; // The submenu (firmwares)
-    //
-    Submenu *submenu_app_list_bluetooth; // The submenu (app list) for Bluetooth
-    Submenu *submenu_app_list_games;     // The submenu (app list) for Games
-    Submenu *submenu_app_list_gpio;      // The submenu (app list) for GPIO
-    Submenu *submenu_app_list_infrared;  // The submenu (app list) for Infrared
-    Submenu *submenu_app_list_ibutton;   // The submenu (app list) for iButton
-    Submenu *submenu_app_list_media;     // The submenu (app list) for Media
-    Submenu *submenu_app_list_nfc;       // The submenu (app list) for NFC
-    Submenu *submenu_app_list_rfid;      // The submenu (app list) for RFID
-    Submenu *submenu_app_list_subghz;    // The submenu (app list) for Sub-GHz
-    Submenu *submenu_app_list_tools;     // The submenu (app list) for Tools
-    Submenu *submenu_app_list_usb;       // The submenu (app list) for USB
-    //
+    Submenu *submenu_options;             // The submenu (options)
+    Submenu *submenu_app_list;            // The submenu (app list) for the selected category
+    Submenu *submenu_firmwares;           // The submenu (firmwares)
+    Submenu *submenu_app_list_category;   // The submenu (app list) for each category
     Widget *widget;                       // The widget
     Popup *popup;                         // The popup
     DialogEx *dialog_delete;              // The dialog for deleting an app

+ 29 - 31
flipper_http/flipper_http.c

@@ -1,8 +1,5 @@
 #include <flipper_http/flipper_http.h>
-FlipperHTTP fhttp;
-char rx_line_buffer[RX_LINE_BUFFER_SIZE];
-uint8_t file_buffer[FILE_BUFFER_SIZE];
-size_t file_buffer_len = 0;
+FlipperHTTP fhttp = {0};
 // Function to append received data to file
 // make sure to initialize the file path before calling this function
 bool flipper_http_append_to_file(
@@ -187,19 +184,19 @@ int32_t flipper_http_worker(void *context)
                 if (fhttp.save_bytes)
                 {
                     // Add byte to the buffer
-                    file_buffer[file_buffer_len++] = c;
+                    fhttp.file_buffer[fhttp.file_buffer_len++] = c;
                     // Write to file if buffer is full
-                    if (file_buffer_len >= FILE_BUFFER_SIZE)
+                    if (fhttp.file_buffer_len >= FILE_BUFFER_SIZE)
                     {
                         if (!flipper_http_append_to_file(
-                                file_buffer,
-                                file_buffer_len,
+                                fhttp.file_buffer,
+                                fhttp.file_buffer_len,
                                 fhttp.just_started_bytes,
                                 fhttp.file_path))
                         {
                             FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
                         }
-                        file_buffer_len = 0;
+                        fhttp.file_buffer_len = 0;
                         fhttp.just_started_bytes = false;
                     }
                 }
@@ -210,17 +207,17 @@ int32_t flipper_http_worker(void *context)
                     // Handle line buffering
                     if (c == '\n' || rx_line_pos >= RX_LINE_BUFFER_SIZE - 1)
                     {
-                        rx_line_buffer[rx_line_pos] = '\0'; // Null-terminate the line
+                        fhttp.rx_line_buffer[rx_line_pos] = '\0'; // Null-terminate the line
 
                         // Invoke the callback with the complete line
-                        fhttp.handle_rx_line_cb(rx_line_buffer, fhttp.callback_context);
+                        fhttp.handle_rx_line_cb(fhttp.rx_line_buffer, fhttp.callback_context);
 
                         // Reset the line buffer position
                         rx_line_pos = 0;
                     }
                     else
                     {
-                        rx_line_buffer[rx_line_pos++] = c; // Add character to the line buffer
+                        fhttp.rx_line_buffer[rx_line_pos++] = c; // Add character to the line buffer
                     }
                 }
             }
@@ -1052,6 +1049,7 @@ bool flipper_http_delete_request_with_headers(
     // The response will be handled asynchronously via the callback
     return true;
 }
+static char *trim(const char *str);
 // Function to handle received data asynchronously
 /**
  * @brief      Callback function to handle received data asynchronously.
@@ -1114,27 +1112,27 @@ void flipper_http_rx_callback(const char *line, void *context)
                 const char marker[] = "[GET/END]";
                 const size_t marker_len = sizeof(marker) - 1; // Exclude null terminator
 
-                for (size_t i = 0; i <= file_buffer_len - marker_len; i++)
+                for (size_t i = 0; i <= fhttp.file_buffer_len - marker_len; i++)
                 {
                     // Check if the marker is found
-                    if (memcmp(&file_buffer[i], marker, marker_len) == 0)
+                    if (memcmp(&fhttp.file_buffer[i], marker, marker_len) == 0)
                     {
                         // Remove the marker by shifting the remaining data left
-                        size_t remaining_len = file_buffer_len - (i + marker_len);
-                        memmove(&file_buffer[i], &file_buffer[i + marker_len], remaining_len);
-                        file_buffer_len -= marker_len;
+                        size_t remaining_len = fhttp.file_buffer_len - (i + marker_len);
+                        memmove(&fhttp.file_buffer[i], &fhttp.file_buffer[i + marker_len], remaining_len);
+                        fhttp.file_buffer_len -= marker_len;
                         break;
                     }
                 }
 
                 // If there is data left in the buffer, append it to the file
-                if (file_buffer_len > 0)
+                if (fhttp.file_buffer_len > 0)
                 {
-                    if (!flipper_http_append_to_file(file_buffer, file_buffer_len, false, fhttp.file_path))
+                    if (!flipper_http_append_to_file(fhttp.file_buffer, fhttp.file_buffer_len, false, fhttp.file_path))
                     {
                         FURI_LOG_E(HTTP_TAG, "Failed to append data to file.");
                     }
-                    file_buffer_len = 0;
+                    fhttp.file_buffer_len = 0;
                 }
             }
 
@@ -1184,27 +1182,27 @@ void flipper_http_rx_callback(const char *line, void *context)
                 const char marker[] = "[POST/END]";
                 const size_t marker_len = sizeof(marker) - 1; // Exclude null terminator
 
-                for (size_t i = 0; i <= file_buffer_len - marker_len; i++)
+                for (size_t i = 0; i <= fhttp.file_buffer_len - marker_len; i++)
                 {
                     // Check if the marker is found
-                    if (memcmp(&file_buffer[i], marker, marker_len) == 0)
+                    if (memcmp(&fhttp.file_buffer[i], marker, marker_len) == 0)
                     {
                         // Remove the marker by shifting the remaining data left
-                        size_t remaining_len = file_buffer_len - (i + marker_len);
-                        memmove(&file_buffer[i], &file_buffer[i + marker_len], remaining_len);
-                        file_buffer_len -= marker_len;
+                        size_t remaining_len = fhttp.file_buffer_len - (i + marker_len);
+                        memmove(&fhttp.file_buffer[i], &fhttp.file_buffer[i + marker_len], remaining_len);
+                        fhttp.file_buffer_len -= marker_len;
                         break;
                     }
                 }
 
                 // If there is data left in the buffer, append it to the file
-                if (file_buffer_len > 0)
+                if (fhttp.file_buffer_len > 0)
                 {
-                    if (!flipper_http_append_to_file(file_buffer, file_buffer_len, false, fhttp.file_path))
+                    if (!flipper_http_append_to_file(fhttp.file_buffer, fhttp.file_buffer_len, false, fhttp.file_path))
                     {
                         FURI_LOG_E(HTTP_TAG, "Failed to append data to file.");
                     }
-                    file_buffer_len = 0;
+                    fhttp.file_buffer_len = 0;
                 }
             }
 
@@ -1332,7 +1330,7 @@ void flipper_http_rx_callback(const char *line, void *context)
         // for GET request, save data only if it's a bytes request
         fhttp.save_bytes = fhttp.is_bytes_request;
         fhttp.just_started_bytes = true;
-        file_buffer_len = 0;
+        fhttp.file_buffer_len = 0;
         return;
     }
     else if (strstr(line, "[POST/SUCCESS]") != NULL)
@@ -1344,7 +1342,7 @@ void flipper_http_rx_callback(const char *line, void *context)
         // for POST request, save data only if it's a bytes request
         fhttp.save_bytes = fhttp.is_bytes_request;
         fhttp.just_started_bytes = true;
-        file_buffer_len = 0;
+        fhttp.file_buffer_len = 0;
         return;
     }
     else if (strstr(line, "[PUT/SUCCESS]") != NULL)
@@ -1400,7 +1398,7 @@ void flipper_http_rx_callback(const char *line, void *context)
 }
 
 // Function to trim leading and trailing spaces and newlines from a constant string
-char *trim(const char *str)
+static char *trim(const char *str)
 {
     const char *end;
     char *trimmed_str;

+ 5 - 7
flipper_http/flipper_http.h

@@ -19,7 +19,7 @@
 #define UART_CH (FuriHalSerialIdUsart)    // UART channel
 #define TIMEOUT_DURATION_TICKS (5 * 1000) // 5 seconds
 #define BAUDRATE (115200)                 // UART baudrate
-#define RX_BUF_SIZE 1024                  // 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 MAX_FILE_SHOW 8192                // Maximum data from file to show
 #define FILE_BUFFER_SIZE 512              // File buffer size
@@ -82,13 +82,13 @@ typedef struct
     bool save_received_data;   // Flag to save the received data to a file
 
     bool just_started_bytes; // Indicates if bytes data reception has just started
+
+    char rx_line_buffer[RX_LINE_BUFFER_SIZE];
+    uint8_t file_buffer[FILE_BUFFER_SIZE];
+    size_t file_buffer_len;
 } FlipperHTTP;
 
 extern FlipperHTTP fhttp;
-// Global static array for the line buffer
-extern char rx_line_buffer[RX_LINE_BUFFER_SIZE];
-extern uint8_t file_buffer[FILE_BUFFER_SIZE];
-extern size_t file_buffer_len;
 
 // fhttp.last_response holds the last received data from the UART
 
@@ -357,8 +357,6 @@ bool flipper_http_delete_request_with_headers(
  */
 void flipper_http_rx_callback(const char *line, void *context);
 
-// Function to trim leading and trailing spaces and newlines from a constant string
-char *trim(const char *str);
 /**
  * @brief Process requests and parse JSON data asynchronously
  * @param http_request The function to send the request