Selaa lähdekoodia

Merge flip_social from https://github.com/jblanked/FlipSocial

# Conflicts:
#	flip_social/alloc/free.c
#	flip_social/flipper_http/flipper_http.h
Willy-JL 8 kuukautta sitten
vanhempi
commit
9bb1b9308c
36 muutettua tiedostoa jossa 4002 lisäystä ja 2639 poistoa
  1. 475 362
      flip_social/alloc/alloc.c
  2. 14 9
      flip_social/alloc/alloc.h
  3. 0 395
      flip_social/alloc/flip_social_alloc.c
  4. 0 13
      flip_social/alloc/flip_social_alloc.h
  5. 0 146
      flip_social/alloc/free.c
  6. 0 15
      flip_social/alloc/free.h
  7. 36 37
      flip_social/app.c
  8. 1 1
      flip_social/application.fam
  9. 8 0
      flip_social/assets/CHANGELOG.md
  10. BIN
      flip_social/assets/flip-social-main-menu.png
  11. 564 164
      flip_social/callback/callback.c
  12. 57 99
      flip_social/callback/callback.h
  13. 590 0
      flip_social/callback/loader.c
  14. 39 0
      flip_social/callback/loader.h
  15. 18 0
      flip_social/callback/utils.h
  16. 50 53
      flip_social/explore/explore.c
  17. 7 0
      flip_social/explore/explore.h
  18. 0 10
      flip_social/explore/flip_social_explore.h
  19. 61 34
      flip_social/feed/feed.c
  20. 9 0
      flip_social/feed/feed.h
  21. 0 11
      flip_social/feed/flip_social_feed.h
  22. 15 126
      flip_social/flip_social.c
  23. 16 4
      flip_social/flip_social.h
  24. 1 1
      flip_social/flip_storage/flip_social_storage.c
  25. 789 687
      flip_social/flipper_http/flipper_http.c
  26. 161 303
      flip_social/flipper_http/flipper_http.h
  27. 356 0
      flip_social/free/free.c
  28. 19 0
      flip_social/free/free.h
  29. 0 10
      flip_social/friends/flip_social_friends.h
  30. 52 32
      flip_social/friends/friends.c
  31. 7 0
      flip_social/friends/friends.h
  32. 0 27
      flip_social/messages/flip_social_messages.h
  33. 82 100
      flip_social/messages/messages.c
  34. 21 0
      flip_social/messages/messages.h
  35. 546 0
      flip_social/update/update.c
  36. 8 0
      flip_social/update/update.h

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 475 - 362
flip_social/alloc/alloc.c


+ 14 - 9
flip_social/alloc/alloc.h

@@ -1,14 +1,19 @@
 #pragma once
 #include <flip_social.h>
-#include <callback/flip_social_callback.h>
-#include <alloc/free.h>
-void auth_headers_alloc(void);
-FlipSocialFeedMini *flip_feed_info_alloc(void);
-bool messages_dialog_alloc(bool free_first);
-bool feed_view_alloc();
-char *updated_user_message(const char *user_message);
+#include <callback/callback.h>
+#include <free/free.h>
+FlipSocialApp *alloc_flip_social_app();
+FlipSocialModel *alloc_friends_model();
+FlipSocialModel2 *alloc_messages();
+FlipSocialMessage *alloc_user_messages();
+FlipSocialModel *alloc_explore();
+void alloc_headers(void);
+FlipSocialFeedMini *alloc_feed_info(void);
+bool allow_messages_dialog(bool free_first);
+bool alloc_feed_view();
+char *alloc_format_message(const char *user_message);
 bool alloc_text_input(uint32_t view_id);
-bool about_widget_alloc(bool is_logged_in);
+bool alloc_about_widget(bool is_logged_in);
 bool alloc_variable_item_list(uint32_t view_id);
 bool alloc_submenu(uint32_t view_id);
-extern bool went_to_friends;
+bool alloc_flipper_http();

+ 0 - 395
flip_social/alloc/flip_social_alloc.c

@@ -1,395 +0,0 @@
-#include <alloc/flip_social_alloc.h>
-
-FlipSocialApp *flip_social_app_alloc()
-{
-    // Initiailize the app
-    FlipSocialApp *app = (FlipSocialApp *)malloc(sizeof(FlipSocialApp));
-
-    // Initialize gui
-    Gui *gui = furi_record_open(RECORD_GUI);
-
-    // Allocate ViewDispatcher
-    if (!easy_flipper_set_view_dispatcher(&app->view_dispatcher, gui, app))
-    {
-        return NULL;
-    }
-    view_dispatcher_set_custom_event_callback(app->view_dispatcher, flip_social_custom_event_callback);
-    // Main view
-    if (!easy_flipper_set_view(&app->view_loader, FlipSocialViewLoader, flip_social_loader_draw_callback, NULL, flip_social_callback_to_submenu_logged_out, &app->view_dispatcher, app))
-    {
-        return NULL;
-    }
-    flip_social_loader_init(app->view_loader);
-    if (!easy_flipper_set_widget(&app->widget_result, FlipSocialViewWidgetResult, "", flip_social_callback_to_submenu_logged_out, &app->view_dispatcher))
-    {
-        return NULL;
-    }
-
-    // Allocate the text input buffers
-    app->wifi_ssid_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->wifi_password_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->login_username_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->login_password_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->register_username_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->register_password_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->register_password_2_logged_out_temp_buffer_size = MAX_USER_LENGTH;
-    app->change_password_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    app->change_bio_logged_in_temp_buffer_size = MAX_MESSAGE_LENGTH;
-    app->compose_pre_save_logged_in_temp_buffer_size = MAX_MESSAGE_LENGTH;
-    app->wifi_ssid_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    app->wifi_password_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    app->is_logged_in_size = 8;
-    app->login_username_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    app->messages_new_message_logged_in_temp_buffer_size = MAX_MESSAGE_LENGTH;
-    app->message_user_choice_logged_in_temp_buffer_size = MAX_MESSAGE_LENGTH;
-    app->explore_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    app->message_users_logged_in_temp_buffer_size = MAX_USER_LENGTH;
-    if (!easy_flipper_set_buffer(&app->wifi_ssid_logged_out_temp_buffer, app->wifi_ssid_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_password_logged_out_temp_buffer, app->wifi_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_username_logged_out_temp_buffer, app->login_username_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_password_logged_out_temp_buffer, app->login_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_username_logged_out_temp_buffer, app->register_username_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_password_logged_out_temp_buffer, app->register_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_password_2_logged_out_temp_buffer, app->register_password_2_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->change_password_logged_in_temp_buffer, app->change_password_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->change_bio_logged_in_temp_buffer, app->change_bio_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->compose_pre_save_logged_in_temp_buffer, app->compose_pre_save_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_ssid_logged_in_temp_buffer, app->wifi_ssid_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_password_logged_in_temp_buffer, app->wifi_password_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->is_logged_in, app->is_logged_in_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_username_logged_in_temp_buffer, app->login_username_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-
-    if (!easy_flipper_set_buffer(&app->wifi_ssid_logged_out, app->wifi_ssid_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_password_logged_out, app->wifi_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_username_logged_out, app->login_username_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_password_logged_out, app->login_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_username_logged_out, app->register_username_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_password_logged_out, app->register_password_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->register_password_2_logged_out, app->register_password_2_logged_out_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->change_password_logged_in, app->change_password_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->change_bio_logged_in, app->change_bio_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->compose_pre_save_logged_in, app->compose_pre_save_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_ssid_logged_in, app->wifi_ssid_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->wifi_password_logged_in, app->wifi_password_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->login_username_logged_in, app->login_username_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    //
-    if (!easy_flipper_set_buffer(&app->messages_new_message_logged_in, app->messages_new_message_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->messages_new_message_logged_in_temp_buffer, app->messages_new_message_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->message_user_choice_logged_in, app->message_user_choice_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->message_user_choice_logged_in_temp_buffer, app->message_user_choice_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&selected_message, app->message_user_choice_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->explore_logged_in, app->explore_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->explore_logged_in_temp_buffer, app->explore_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->message_users_logged_in, app->message_users_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_buffer(&app->message_users_logged_in_temp_buffer, app->message_users_logged_in_temp_buffer_size))
-    {
-        return NULL;
-    }
-
-    // Allocate Submenu(s)
-    if (!easy_flipper_set_submenu(&app->submenu_logged_out, FlipSocialViewLoggedOutSubmenu, VERSION_TAG, flip_social_callback_exit_app, &app->view_dispatcher))
-    {
-        return NULL;
-    }
-    if (!easy_flipper_set_submenu(&app->submenu_logged_in, FlipSocialViewLoggedInSubmenu, VERSION_TAG, flip_social_callback_exit_app, &app->view_dispatcher))
-    {
-        return NULL;
-    }
-
-    submenu_add_item(app->submenu_logged_out, "Login", FlipSocialSubmenuLoggedOutIndexLogin, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_out, "Register", FlipSocialSubmenuLoggedOutIndexRegister, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_out, "About", FlipSocialSubmenuLoggedOutIndexAbout, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_out, "Settings", FlipSocialSubmenuLoggedOutIndexWifiSettings, flip_social_callback_submenu_choices, app);
-    //
-    submenu_add_item(app->submenu_logged_in, "Explore", FlipSocialSubmenuExploreIndex, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Feed", FlipSocialSubmenuLoggedInIndexFeed, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Post", FlipSocialSubmenuLoggedInIndexCompose, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Messages", FlipSocialSubmenuLoggedInIndexMessages, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Profile", FlipSocialSubmenuLoggedInIndexProfile, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Settings", FlipSocialSubmenuLoggedInIndexSettings, flip_social_callback_submenu_choices, app);
-    submenu_add_item(app->submenu_logged_in, "Sign Out", FlipSocialSubmenuLoggedInSignOutButton, flip_social_callback_submenu_choices, app);
-
-    // Load the settings
-    if (!load_settings(app->wifi_ssid_logged_out,
-                       app->wifi_ssid_logged_out_temp_buffer_size,
-                       app->wifi_password_logged_out,
-                       app->wifi_password_logged_out_temp_buffer_size,
-                       app->login_username_logged_out,
-                       app->login_username_logged_out_temp_buffer_size,
-                       app->login_username_logged_in,
-                       app->login_username_logged_in_temp_buffer_size,
-                       app->login_password_logged_out,
-                       app->login_password_logged_out_temp_buffer_size,
-                       app->change_password_logged_in,
-                       app->change_password_logged_in_temp_buffer_size,
-                       app->change_bio_logged_in,
-                       app->change_bio_logged_in_temp_buffer_size,
-                       app->is_logged_in,
-                       app->is_logged_in_size))
-
-    {
-        FURI_LOG_E(TAG, "Failed to load settings");
-
-        if (app->is_logged_in == NULL)
-        {
-            app->is_logged_in = (char *)malloc(app->is_logged_in_size);
-            app->is_logged_in = "false";
-        }
-        app_instance = app;
-        view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
-    }
-    else
-    {
-        // Copy items into their temp buffers with safety checks
-        if (app->wifi_ssid_logged_out && app->wifi_ssid_logged_out_temp_buffer)
-        {
-            strncpy(app->wifi_ssid_logged_out_temp_buffer, app->wifi_ssid_logged_out, app->wifi_ssid_logged_out_temp_buffer_size - 1);
-            app->wifi_ssid_logged_out_temp_buffer[app->wifi_ssid_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->wifi_password_logged_out && app->wifi_password_logged_out_temp_buffer)
-        {
-            strncpy(app->wifi_password_logged_out_temp_buffer, app->wifi_password_logged_out, app->wifi_password_logged_out_temp_buffer_size - 1);
-            app->wifi_password_logged_out_temp_buffer[app->wifi_password_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->login_username_logged_out && app->login_username_logged_out_temp_buffer)
-        {
-            strncpy(app->login_username_logged_out_temp_buffer, app->login_username_logged_out, app->login_username_logged_out_temp_buffer_size - 1);
-            app->login_username_logged_out_temp_buffer[app->login_username_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->login_password_logged_out && app->login_password_logged_out_temp_buffer)
-        {
-            strncpy(app->login_password_logged_out_temp_buffer, app->login_password_logged_out, app->login_password_logged_out_temp_buffer_size - 1);
-            app->login_password_logged_out_temp_buffer[app->login_password_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->register_username_logged_out && app->register_username_logged_out_temp_buffer)
-        {
-            strncpy(app->register_username_logged_out_temp_buffer, app->register_username_logged_out, app->register_username_logged_out_temp_buffer_size - 1);
-            app->register_username_logged_out_temp_buffer[app->register_username_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->register_password_logged_out && app->register_password_logged_out_temp_buffer)
-        {
-            strncpy(app->register_password_logged_out_temp_buffer, app->register_password_logged_out, app->register_password_logged_out_temp_buffer_size - 1);
-            app->register_password_logged_out_temp_buffer[app->register_password_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->register_password_2_logged_out && app->register_password_2_logged_out_temp_buffer)
-        {
-            strncpy(app->register_password_2_logged_out_temp_buffer, app->register_password_2_logged_out, app->register_password_2_logged_out_temp_buffer_size - 1);
-            app->register_password_2_logged_out_temp_buffer[app->register_password_2_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        if (app->change_password_logged_in && app->change_password_logged_in_temp_buffer)
-        {
-            strncpy(app->change_password_logged_in_temp_buffer, app->change_password_logged_in, app->change_password_logged_in_temp_buffer_size - 1);
-            app->change_password_logged_in_temp_buffer[app->change_password_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        if (app->change_bio_logged_in && app->change_bio_logged_in_temp_buffer)
-        {
-            strncpy(app->change_bio_logged_in_temp_buffer, app->change_bio_logged_in, app->change_bio_logged_in_temp_buffer_size - 1);
-            app->change_bio_logged_in_temp_buffer[app->change_bio_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        if (app->compose_pre_save_logged_in && app->compose_pre_save_logged_in_temp_buffer)
-        {
-            strncpy(app->compose_pre_save_logged_in_temp_buffer, app->compose_pre_save_logged_in, app->compose_pre_save_logged_in_temp_buffer_size - 1);
-            app->compose_pre_save_logged_in_temp_buffer[app->compose_pre_save_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        if (app->wifi_ssid_logged_in && app->wifi_ssid_logged_in_temp_buffer)
-        {
-            strncpy(app->wifi_ssid_logged_in_temp_buffer, app->wifi_ssid_logged_in, app->wifi_ssid_logged_in_temp_buffer_size - 1);
-            app->wifi_ssid_logged_in_temp_buffer[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        if (app->wifi_password_logged_in && app->wifi_password_logged_in_temp_buffer)
-        {
-            strncpy(app->wifi_password_logged_in_temp_buffer, app->wifi_password_logged_in, app->wifi_password_logged_in_temp_buffer_size - 1);
-            app->wifi_password_logged_in_temp_buffer[app->wifi_password_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        if (app->login_username_logged_in && app->login_username_logged_in_temp_buffer)
-        {
-            strncpy(app->login_username_logged_in_temp_buffer, app->login_username_logged_in, app->login_username_logged_in_temp_buffer_size - 1);
-            app->login_username_logged_in_temp_buffer[app->login_username_logged_in_temp_buffer_size - 1] = '\0';
-        }
-
-        // if login username is empty but logged out isnt, copy it over
-        if (strlen(app->login_username_logged_out) > 0 && strlen(app->login_username_logged_in) == 0)
-        {
-            strncpy(app->login_username_logged_in, app->login_username_logged_out, app->login_username_logged_in_temp_buffer_size - 1);
-            strncpy(app->login_username_logged_in_temp_buffer, app->login_username_logged_out, app->login_username_logged_in_temp_buffer_size - 1);
-            app->login_username_logged_in[app->login_username_logged_in_temp_buffer_size - 1] = '\0';
-            app->login_username_logged_in_temp_buffer[app->login_username_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        // logout username is empty but logged in isnt, copy it over
-        if (strlen(app->login_username_logged_in) > 0 && strlen(app->login_username_logged_out) == 0)
-        {
-            strncpy(app->login_username_logged_out, app->login_username_logged_in, app->login_username_logged_in_temp_buffer_size - 1);
-            strncpy(app->login_username_logged_out_temp_buffer, app->login_username_logged_in, app->login_username_logged_in_temp_buffer_size - 1);
-            app->login_username_logged_out[app->login_username_logged_in_temp_buffer_size - 1] = '\0';
-            app->login_username_logged_out_temp_buffer[app->login_username_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        // if login password is empty but logged out isnt, copy it over
-        if (strlen(app->login_password_logged_out) > 0 && strlen(app->change_password_logged_in) == 0)
-        {
-            strncpy(app->change_password_logged_in, app->login_password_logged_out, app->login_password_logged_out_temp_buffer_size - 1);
-            strncpy(app->change_password_logged_in_temp_buffer, app->login_password_logged_out, app->login_password_logged_out_temp_buffer_size - 1);
-            app->change_password_logged_in[app->login_password_logged_out_temp_buffer_size - 1] = '\0';
-            app->change_password_logged_in_temp_buffer[app->login_password_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        // if logout password is empty but logged in isnt, copy it over
-        if (strlen(app->change_password_logged_in) > 0 && strlen(app->login_password_logged_out) == 0)
-        {
-            strncpy(app->login_password_logged_out, app->change_password_logged_in, app->login_password_logged_out_temp_buffer_size - 1);
-            strncpy(app->login_password_logged_out_temp_buffer, app->change_password_logged_in, app->login_password_logged_out_temp_buffer_size - 1);
-            app->login_password_logged_out[app->login_password_logged_out_temp_buffer_size - 1] = '\0';
-            app->login_password_logged_out_temp_buffer[app->login_password_logged_out_temp_buffer_size - 1] = '\0';
-        }
-        // if wifi password is empty but logged out isnt, copy it over
-        if (strlen(app->wifi_password_logged_out) > 0 && strlen(app->wifi_password_logged_in) == 0)
-        {
-            strncpy(app->wifi_password_logged_in, app->wifi_password_logged_out, app->wifi_password_logged_in_temp_buffer_size - 1);
-            strncpy(app->wifi_password_logged_in_temp_buffer, app->wifi_password_logged_out, app->wifi_password_logged_in_temp_buffer_size - 1);
-            app->wifi_password_logged_in[app->wifi_password_logged_in_temp_buffer_size - 1] = '\0';
-            app->wifi_password_logged_in_temp_buffer[app->wifi_password_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        // ifi wifi password is empty but logged in isnt, copy it over
-        if (strlen(app->wifi_password_logged_in) > 0 && strlen(app->wifi_password_logged_out) == 0)
-        {
-            strncpy(app->wifi_password_logged_out, app->wifi_password_logged_in, app->wifi_password_logged_in_temp_buffer_size - 1);
-            strncpy(app->wifi_password_logged_out_temp_buffer, app->wifi_password_logged_in, app->wifi_password_logged_in_temp_buffer_size - 1);
-            app->wifi_password_logged_out[app->wifi_password_logged_in_temp_buffer_size - 1] = '\0';
-            app->wifi_password_logged_out_temp_buffer[app->wifi_password_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        // if wifi ssid is empty but logged out isnt, copy it over
-        if (strlen(app->wifi_ssid_logged_out) > 0 && strlen(app->wifi_ssid_logged_in) == 0)
-        {
-            strncpy(app->wifi_ssid_logged_in, app->wifi_ssid_logged_out, app->wifi_ssid_logged_in_temp_buffer_size - 1);
-            strncpy(app->wifi_ssid_logged_in_temp_buffer, app->wifi_ssid_logged_out, app->wifi_ssid_logged_in_temp_buffer_size - 1);
-            app->wifi_ssid_logged_in[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
-            app->wifi_ssid_logged_in_temp_buffer[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
-        }
-        // if wifi ssid is empty but logged in isnt, copy it over
-        if (strlen(app->wifi_ssid_logged_in) > 0 && strlen(app->wifi_ssid_logged_out) == 0)
-        {
-            strncpy(app->wifi_ssid_logged_out, app->wifi_ssid_logged_in, app->wifi_ssid_logged_in_temp_buffer_size - 1);
-            strncpy(app->wifi_ssid_logged_out_temp_buffer, app->wifi_ssid_logged_in, app->wifi_ssid_logged_in_temp_buffer_size - 1);
-            app->wifi_ssid_logged_out[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
-            app->wifi_ssid_logged_out_temp_buffer[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
-        }
-
-        auth_headers_alloc();
-
-        if (app->is_logged_in != NULL && strcmp(app->is_logged_in, "true") == 0)
-        {
-            save_char("is_logged_in", "true");
-            view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-        }
-        else
-        {
-            save_char("is_logged_in", "false");
-            view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
-        }
-    }
-
-    return app;
-}

+ 0 - 13
flip_social/alloc/flip_social_alloc.h

@@ -1,13 +0,0 @@
-#ifndef FLIP_SOCIAL_ALLOC_H
-#define FLIP_SOCIAL_ALLOC_H
-#include <flip_social.h>
-#include <callback/flip_social_callback.h>
-#include <flip_storage/flip_social_storage.h>
-
-/**
- * @brief Function to allocate resources for the FlipSocialApp.
- * @details Initializes all components and views of the application.
- * @return Pointer to the initialized FlipSocialApp, or NULL on failure.
- */
-FlipSocialApp *flip_social_app_alloc();
-#endif

+ 0 - 146
flip_social/alloc/free.c

@@ -1,146 +0,0 @@
-#include <alloc/free.h>
-void free_all(bool should_free_variable_item_list, bool should_free_submenu)
-{
-
-    if (should_free_submenu)
-    {
-        flip_social_free_explore();
-        free_submenu();
-    }
-    if (should_free_variable_item_list)
-    {
-        free_variable_item_list();
-    }
-    free_text_input();
-    flip_social_free_friends();
-    flip_social_free_messages();
-    flip_social_free_feed_view();
-    flip_social_free_compose_dialog();
-    flip_social_free_explore_dialog();
-    flip_social_free_friends_dialog();
-    flip_social_free_messages_dialog();
-    flip_feed_info_free();
-    free_about_widget(true);
-    free_about_widget(false);
-
-    if (went_to_friends)
-    {
-        flipper_http_deinit();
-        went_to_friends = false;
-    }
-}
-void free_text_input()
-{
-    if (app_instance->text_input)
-    {
-        text_input_free(app_instance->text_input);
-        app_instance->text_input = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewTextInput);
-    }
-}
-void flip_social_free_explore_dialog()
-{
-    if (app_instance->dialog_explore)
-    {
-        dialog_ex_free(app_instance->dialog_explore);
-        app_instance->dialog_explore = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewExploreDialog);
-    }
-}
-void flip_social_free_friends_dialog()
-{
-    if (app_instance->dialog_friends)
-    {
-        dialog_ex_free(app_instance->dialog_friends);
-        app_instance->dialog_friends = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewFriendsDialog);
-    }
-}
-void flip_social_free_messages_dialog()
-{
-    if (app_instance->dialog_messages)
-    {
-        dialog_ex_free(app_instance->dialog_messages);
-        app_instance->dialog_messages = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewMessagesDialog);
-        return;
-    }
-}
-void flip_social_free_compose_dialog()
-{
-    if (app_instance->dialog_compose)
-    {
-        dialog_ex_free(app_instance->dialog_compose);
-        app_instance->dialog_compose = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewComposeDialog);
-    }
-}
-void flip_social_free_feed_view()
-{
-    if (app_instance->view_feed)
-    {
-        view_free(app_instance->view_feed);
-        app_instance->view_feed = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
-    }
-}
-
-void free_about_widget(bool is_logged_in)
-{
-    if (is_logged_in && app_instance->widget_logged_in_about)
-    {
-        widget_free(app_instance->widget_logged_in_about);
-        app_instance->widget_logged_in_about = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSettingsAbout);
-    }
-    if (!is_logged_in && app_instance->widget_logged_out_about)
-    {
-        widget_free(app_instance->widget_logged_out_about);
-        app_instance->widget_logged_out_about = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedOutAbout);
-    }
-}
-
-void flip_social_free_friends(void)
-{
-    if (!flip_social_friends)
-    {
-        return;
-    }
-    free(flip_social_friends);
-    flip_social_friends = NULL;
-}
-
-void flip_feed_info_free(void)
-{
-    if (!flip_feed_info)
-    {
-        return;
-    }
-    free(flip_feed_info);
-    flip_feed_info = NULL;
-}
-
-void free_variable_item_list(void)
-{
-    if (app_instance->variable_item_list)
-    {
-        variable_item_list_free(app_instance->variable_item_list);
-        app_instance->variable_item_list = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewVariableItemList);
-    }
-}
-
-void free_submenu(void)
-{
-    if (!app_instance)
-    {
-        return;
-    }
-    if (app_instance->submenu)
-    {
-        submenu_free(app_instance->submenu);
-        app_instance->submenu = NULL;
-        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewSubmenu);
-    }
-}

+ 0 - 15
flip_social/alloc/free.h

@@ -1,15 +0,0 @@
-#pragma once
-#include <flip_social.h>
-#include <callback/flip_social_callback.h>
-void free_all(bool should_free_variable_item_list, bool should_free_submenu);
-void free_text_input();
-void flip_social_free_explore_dialog();
-void flip_social_free_friends_dialog();
-void flip_social_free_messages_dialog();
-void flip_social_free_compose_dialog();
-void flip_social_free_feed_view();
-void free_about_widget(bool is_logged_in);
-void flip_social_free_friends(void);
-void flip_feed_info_free(void);
-void free_variable_item_list(void);
-void free_submenu(void);

+ 36 - 37
flip_social/app.c

@@ -1,6 +1,7 @@
-// app.c
-#include <flip_social.h>             // Include the FlipSocialApp structure
-#include <alloc/flip_social_alloc.h> // Include the allocation functions
+#include <flip_social.h>
+#include <alloc/alloc.h>
+#include <flip_storage/flip_social_storage.h>
+#include <update/update.h>
 
 /**
  * @brief Entry point for the Hello World application.
@@ -13,7 +14,7 @@ int32_t main_flip_social(void *p)
     UNUSED(p);
 
     // Initialize the Hello World application
-    app_instance = flip_social_app_alloc();
+    app_instance = alloc_flip_social_app();
     if (!app_instance)
     {
         // Allocation failed
@@ -22,43 +23,34 @@ int32_t main_flip_social(void *p)
     }
 
     // check if board is connected (Derek Jamison)
-    uint8_t counter = 10;
-    // initialize the http
-    if (flipper_http_init(flipper_http_rx_callback, app_instance))
+    if (!alloc_flipper_http())
     {
-        fhttp.state = INACTIVE; // set inactive for the ping
-
-        if (!flipper_http_ping())
-        {
-            FURI_LOG_E(TAG, "Failed to ping the device");
-            return -1;
-        }
-
-        // Try to wait for pong response.
-        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.");
-        }
-        else
-        {
-            save_char("is_connected", "true");
-        }
+        easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
+        return -1;
+    }
 
-        flipper_http_deinit();
+    if (!flipper_http_send_command(app_instance->fhttp, HTTP_CMD_PING))
+    {
+        FURI_LOG_E(TAG, "Failed to ping the device");
+        free_flipper_http();
+        return -1;
     }
-    else
+
+    // Try to wait for pong response.
+    uint32_t counter = 10;
+    while (app_instance->fhttp->state == INACTIVE && --counter > 0)
     {
-        easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
+        FURI_LOG_D(TAG, "Waiting for PONG");
+        furi_delay_ms(100);
     }
+    // save app version
+    save_char("app_version", VERSION);
 
-    // if counter is not 0, check notifications
-    if (counter != 0)
+    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.");
+    }
+    else
     {
         char is_connected[5];
         char is_logged_in[5];
@@ -71,15 +63,22 @@ int32_t main_flip_social(void *p)
             strcmp(is_notifications, "on") == 0 &&
             strcmp(is_logged_in, "true") == 0)
         {
-            flip_social_home_notification();
+            callback_home_notification(app_instance->fhttp);
+        }
+
+        if (update_is_ready(app_instance->fhttp, true))
+        {
+            easy_flipper_dialog("Update Status", "Complete.\nRestart your Flipper Zero.");
         }
     }
 
+    free_flipper_http();
+
     // Run the view dispatcher
     view_dispatcher_run(app_instance->view_dispatcher);
 
     // Free the resources used by the Hello World application
-    flip_social_app_free(app_instance);
+    free_flip_social_app(app_instance);
 
     // Return 0 to indicate success
     return 0;

+ 1 - 1
flip_social/application.fam

@@ -9,6 +9,6 @@ App(
     fap_icon_assets="assets",
     fap_author="JBlanked",
     fap_weburl="https://github.com/jblanked/FlipSocial",
-    fap_version="1.0.4",
+    fap_version="1.1",
     fap_description="Social media platform for the Flipper Zero.",
 )

+ 8 - 0
flip_social/assets/CHANGELOG.md

@@ -1,3 +1,11 @@
+## 1.1
+- Restructured code.
+- Added auto‑updating.
+- Updated login and registration views to display errors.
+- Reduced maximum feed posts from 20 to 12 per batch for faster parsing.
+- Fixed an out‑of‑memory crash in the Friends view.
+- Fixed several bugs.
+
 ## 1.0.4
 - New server backend.
 

BIN
flip_social/assets/flip-social-main-menu.png


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 564 - 164
flip_social/callback/callback.c


+ 57 - 99
flip_social/callback/flip_social_callback.h → flip_social/callback/callback.h

@@ -1,112 +1,120 @@
 #ifndef FLIP_SOCIAL_CALLBACK_H
 #define FLIP_SOCIAL_CALLBACK_H
-
 #include <flip_social.h>
-#include <messages/flip_social_messages.h>
-#include <friends/flip_social_friends.h>
-#include <explore/flip_social_explore.h>
-#include <feed/flip_social_feed.h>
-#include <flip_storage/flip_social_storage.h>
-#include <alloc/free.h>
-#include <alloc/alloc.h>
+
+// replica of flipper_http_load_task but allows FlipperHTTP to be passed in
+typedef bool (*LoadingCallback)(FlipperHTTP *);
+
+void callback_loading_task(FlipperHTTP *fhttp,
+                           LoadingCallback http_request,
+                           LoadingCallback parse_response,
+                           uint32_t success_view_id,
+                           uint32_t failure_view_id,
+                           ViewDispatcher **view_dispatcher,
+                           bool should_free_loader);
+
+bool callback_request_await(FlipperHTTP *fhttp, LoadingCallback http_request, LoadingCallback parse_response);
 
 /**
  * @brief Navigation callback to go back to the submenu Logged out.
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedOutSubmenu)
  */
-uint32_t flip_social_callback_to_submenu_logged_out(void *context);
+uint32_t callback_to_submenu_logged_out(void *context);
 
 /**
  * @brief Navigation callback to go back to the submenu Logged in.
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInSubmenu)
  */
-uint32_t flip_social_callback_to_submenu_logged_in(void *context);
+uint32_t callback_to_submenu_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged out) Login screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedOutLogin)
  */
-uint32_t flip_social_callback_to_login_logged_out(void *context);
+uint32_t callback_to_login_logged_out(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged out) Register screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedOutRegister)
  */
-uint32_t flip_social_callback_to_register_logged_out(void *context);
+uint32_t callback_to_register_logged_out(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged out) Wifi Settings screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedOutWifiSettings)
  */
-uint32_t flip_social_callback_to_wifi_settings_logged_out(void *context);
+uint32_t callback_to_wifi_settings_logged_out(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged in) Wifi Settings screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInSettingsWifi)
  */
-uint32_t flip_social_callback_to_wifi_settings_logged_in(void *context);
+uint32_t callback_to_wifi_settings_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged in) Settings screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInSettingsWifi)
  */
-uint32_t flip_social_callback_to_settings_logged_in(void *context);
+uint32_t callback_to_settings_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged in) Compose screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInCompose)
  */
-uint32_t flip_social_callback_to_compose_logged_in(void *context);
+uint32_t callback_to_compose_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the (Logged in) Profile screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInProfile)
  */
-uint32_t flip_social_callback_to_profile_logged_in(void *context);
+uint32_t callback_to_profile_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the Explore submenu
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInExploreSubmenu)
  */
-uint32_t flip_social_callback_to_explore_logged_in(void *context);
+uint32_t callback_to_explore_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the Friends submenu
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInFriendsSubmenu)
  */
-uint32_t flip_social_callback_to_friends_logged_in(void *context);
+uint32_t callback_to_friends_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the Messages submenu
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInMessagesSubmenu)
  */
-uint32_t flip_social_callback_to_messages_logged_in(void *context);
+uint32_t callback_to_messages_logged_in(void *context);
 
 /**
  * @brief Navigation callback to bring the user back to the User Choices screen
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedInMessagesUserChoices)
  */
-uint32_t flip_social_callback_to_messages_user_choices(void *context);
+uint32_t callback_to_messages_user_choices(void *context);
 
 /**
  * @brief Navigation callback for exiting the application
  * @param context The context - unused
  * @return next view id (VIEW_NONE to exit the app)
  */
-uint32_t flip_social_callback_exit_app(void *context);
+uint32_t callback_exit_app(void *context);
+
+void callback_feed_draw(Canvas *canvas, void *model);
+bool callback_feed_input(InputEvent *event, void *context);
 
 /**
  * @brief Handle ALL submenu item selections.
@@ -114,21 +122,21 @@ uint32_t flip_social_callback_exit_app(void *context);
  * @param index The FlipSocialSubmenuIndex item that was clicked.
  * @return void
  */
-void flip_social_callback_submenu_choices(void *context, uint32_t index);
+void callback_submenu_choices(void *context, uint32_t index);
 
 /**
  * @brief Text input callback for when the user finishes entering their SSID on the wifi settings (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_wifi_settings_ssid_updated(void *context);
+void callback_logged_out_wifi_settings_ssid_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their password on the wifi settings (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_wifi_settings_password_updated(void *context);
+void callback_logged_out_wifi_settings_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the wifi settings (logged out) screen.
@@ -136,21 +144,21 @@ void flip_social_logged_out_wifi_settings_password_updated(void *context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_text_input_logged_out_wifi_settings_item_selected(void *context, uint32_t index);
+void callback_logged_out_wifi_settings_item_selected(void *context, uint32_t index);
 
 /**
  * @brief Text input callback for when the user finishes entering their username on the login (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_login_username_updated(void *context);
+void callback_logged_out_login_username_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their password on the login (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_login_password_updated(void *context);
+void callback_logged_out_login_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the login (logged out) screen.
@@ -158,42 +166,42 @@ void flip_social_logged_out_login_password_updated(void *context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_text_input_logged_out_login_item_selected(void *context, uint32_t index);
+void callback_logged_out_login_item_selected(void *context, uint32_t index);
 
 /**
  * @brief Text input callback for when the user finishes entering their username on the register (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_register_username_updated(void *context);
+void callback_logged_out_register_username_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their password on the register (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_register_password_updated(void *context);
+void callback_logged_out_register_password_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their password 2 on the register (logged out) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_out_register_password_2_updated(void *context);
+void callback_logged_out_register_password_2_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their SSID on the wifi settings (logged in) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_wifi_settings_ssid_updated(void *context);
+void callback_logged_in_wifi_settings_ssid_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their password on the wifi settings (logged in) screen.
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_wifi_settings_password_updated(void *context);
+void callback_logged_in_wifi_settings_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the wifi settings (logged in) screen.
@@ -201,21 +209,21 @@ void flip_social_logged_in_wifi_settings_password_updated(void *context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_text_input_logged_in_wifi_settings_item_selected(void *context, uint32_t index);
+void callback_logged_in_wifi_settings_item_selected(void *context, uint32_t index);
 
 /**
  * @brief Text input callback for when the user finishes entering their message on the compose (logged in) screen for Add Text
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_compose_pre_save_updated(void *context);
+void callback_logged_in_compose_pre_save_updated(void *context);
 
 /**
  * @brief Text input callback for when the user finishes entering their message on the profile (logged in) screen for change password
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_profile_change_password_updated(void *context);
+void callback_logged_in_profile_change_password_updated(void *context);
 
 /**
  * @brief Callback when a user selects a menu item in the profile (logged in) screen.
@@ -223,29 +231,22 @@ void flip_social_logged_in_profile_change_password_updated(void *context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_logged_in_profile_change_bio_updated(void *context);
-void flip_social_text_input_logged_in_profile_item_selected(void *context, uint32_t index);
-
-/**
- * @brief Callback when a user selects a menu item in the settings (logged in) screen.
- * @param context The context - FlipSocialApp object.
- * @param index The index of the selected item.
- * @return void
- */
-void flip_social_text_input_logged_in_settings_item_selected(void *context, uint32_t index);
+void callback_logged_in_profile_change_bio_updated(void *context);
+void callback_logged_in_profile_item_selected(void *context, uint32_t index);
 
 /**
  * @brief Text input callback for when the user finishes entering their message to send to the selected user choice (user choice messages view)
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_messages_user_choice_message_updated(void *context);
+void callback_logged_in_messages_user_choice_message_updated(void *context);
+
 /**
  * @brief Text input callback for when the user finishes entering their message to the selected user (messages view)
  * @param context The context - FlipSocialApp object.
  * @return void
  */
-void flip_social_logged_in_messages_new_message_updated(void *context);
+void callback_logged_in_messages_new_message_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the register (logged out) screen.
@@ -253,55 +254,12 @@ void flip_social_logged_in_messages_new_message_updated(void *context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_text_input_logged_out_register_item_selected(void *context, uint32_t index);
-void flip_social_logged_in_user_settings_item_selected(void *context, uint32_t index);
-void flip_social_logged_in_explore_updated(void *context);
-void flip_social_logged_in_message_users_updated(void *context);
-
-// Add edits by Derek Jamison
-typedef enum DataState DataState;
-enum DataState
-{
-    DataStateInitial,
-    DataStateRequested,
-    DataStateReceived,
-    DataStateParsed,
-    DataStateParseError,
-    DataStateError,
-};
-
-typedef enum FlipSocialCustomEvent FlipSocialCustomEvent;
-enum FlipSocialCustomEvent
-{
-    FlipSocialCustomEventProcess,
-};
-
-typedef struct DataLoaderModel DataLoaderModel;
-typedef bool (*DataLoaderFetch)(DataLoaderModel *model);
-typedef char *(*DataLoaderParser)(DataLoaderModel *model);
-struct DataLoaderModel
-{
-    char *title;
-    char *data_text;
-    DataState data_state;
-    DataLoaderFetch fetcher;
-    DataLoaderParser parser;
-    void *parser_context;
-    size_t request_index;
-    size_t request_count;
-    ViewNavigationCallback back_callback;
-    FuriTimer *timer;
-};
-void flip_social_generic_switch_to_view(FlipSocialApp *app, char *title, DataLoaderFetch fetcher, DataLoaderParser parser, size_t request_count, ViewNavigationCallback back, uint32_t view_id);
-
-void flip_social_loader_draw_callback(Canvas *canvas, void *model);
-
-void flip_social_loader_init(View *view);
-
-void flip_social_loader_free_model(View *view);
-bool flip_social_custom_event_callback(void *context, uint32_t index);
-void messages_dialog_callback(DialogExResult result, void *context);
-void feed_dialog_callback(DialogExResult result, void *context);
+void callback_logged_out_register_item_selected(void *context, uint32_t index);
+void callback_logged_in_user_settings_item_selected(void *context, uint32_t index);
+void callback_logged_in_explore_updated(void *context);
+void callback_logged_in_message_users_updated(void *context);
+
+void callback_message_dialog(DialogExResult result, void *context);
 //
-bool flip_social_home_notification();
+bool callback_home_notification(FlipperHTTP *fhttp);
 #endif

+ 590 - 0
flip_social/callback/loader.c

@@ -0,0 +1,590 @@
+#include <callback/loader.h>
+#include <callback/utils.h>
+#include <alloc/alloc.h>
+
+bool loader_view_alloc(void *context)
+{
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    furi_check(app, "FlipSocialApp is NULL");
+    if (app->view_loader)
+    {
+        FURI_LOG_E(TAG, "View loader already allocated");
+        return false;
+    }
+    if (app->widget_result)
+    {
+        FURI_LOG_E(TAG, "Widget result already allocated");
+        return false;
+    }
+
+    view_dispatcher_set_custom_event_callback(app->view_dispatcher, loader_custom_event_callback);
+
+    if (!easy_flipper_set_view(&app->view_loader, FlipSocialViewLoader, loader_draw_callback, NULL, callback_to_submenu_logged_in, &app->view_dispatcher, app))
+    {
+        return false;
+    }
+
+    loader_init(app->view_loader);
+
+    return easy_flipper_set_widget(&app->widget_result, FlipSocialViewWidgetResult, "", callback_to_submenu_logged_in, &app->view_dispatcher);
+}
+
+void loader_view_free(void *context)
+{
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    furi_check(app, "FlipSocialApp is NULL");
+    // Free Widget(s)
+    if (app->widget_result)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewWidgetResult);
+        widget_free(app->widget_result);
+        app->widget_result = NULL;
+    }
+
+    // Free View(s)
+    if (app->view_loader)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoader);
+        loader_free_model(app->view_loader);
+        view_free(app->view_loader);
+        app->view_loader = NULL;
+    }
+}
+
+static void loader_error_draw(Canvas *canvas, DataLoaderModel *model)
+{
+    if (canvas == NULL)
+    {
+        FURI_LOG_E(TAG, "error_draw - canvas is NULL");
+        DEV_CRASH();
+        return;
+    }
+    if (model->fhttp->last_response != NULL)
+    {
+        if (strstr(model->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(model->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 if (strstr(model->fhttp->last_response, "[ERROR] GET request failed or returned empty data.") != NULL)
+        {
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "[ERROR] WiFi error.");
+            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
+            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
+        }
+        else if (strstr(model->fhttp->last_response, "[PONG]") != NULL)
+        {
+            canvas_clear(canvas);
+            canvas_draw_str(canvas, 0, 10, "[STATUS]Connecting to AP...");
+        }
+        else
+        {
+            canvas_clear(canvas);
+            FURI_LOG_E(TAG, "Received an error: %s", model->fhttp->last_response);
+            canvas_draw_str(canvas, 0, 10, "[ERROR] Unusual error...");
+            canvas_draw_str(canvas, 0, 60, "Press BACK and retry.");
+        }
+    }
+    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.");
+    }
+}
+
+static void loader_process_callback(void *context)
+{
+    if (context == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_process_callback - context is NULL");
+        DEV_CRASH();
+        return;
+    }
+
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    View *view = app->view_loader;
+
+    DataState current_data_state;
+    DataLoaderModel *loader_model = NULL;
+    with_view_model(
+        view,
+        DataLoaderModel * model,
+        {
+            current_data_state = model->data_state;
+            loader_model = model;
+        },
+        false);
+    if (!loader_model || !loader_model->fhttp)
+    {
+        FURI_LOG_E(TAG, "Model or fhttp is NULL");
+        DEV_CRASH();
+        return;
+    }
+
+    if (current_data_state == DataStateInitial)
+    {
+        with_view_model(
+            view,
+            DataLoaderModel * model,
+            {
+                model->data_state = DataStateRequested;
+                DataLoaderFetch fetch = model->fetcher;
+                if (fetch == NULL)
+                {
+                    FURI_LOG_E(TAG, "Model doesn't have Fetch function assigned.");
+                    model->data_state = DataStateError;
+                    return;
+                }
+
+                // Clear any previous responses
+                strncpy(model->fhttp->last_response, "", 1);
+                bool request_status = fetch(model);
+                if (!request_status)
+                {
+                    model->data_state = DataStateError;
+                }
+            },
+            true);
+    }
+    else if (current_data_state == DataStateRequested || current_data_state == DataStateError)
+    {
+        if (loader_model->fhttp->state == IDLE && loader_model->fhttp->last_response != NULL)
+        {
+            if (strstr(loader_model->fhttp->last_response, "[PONG]") != NULL)
+            {
+                FURI_LOG_DEV(TAG, "PONG received.");
+            }
+            else if (strncmp(loader_model->fhttp->last_response, "[SUCCESS]", 9))
+            {
+                FURI_LOG_DEV(TAG, "SUCCESS received. %s", loader_model->fhttp->last_response ? loader_model->fhttp->last_response : "NULL");
+            }
+            else if (strncmp(loader_model->fhttp->last_response, "[ERROR]", 9))
+            {
+                FURI_LOG_DEV(TAG, "ERROR received. %s", loader_model->fhttp->last_response ? loader_model->fhttp->last_response : "NULL");
+            }
+            else if (strlen(loader_model->fhttp->last_response))
+            {
+                // Still waiting on response
+            }
+            else
+            {
+                with_view_model(view, DataLoaderModel * model, { model->data_state = DataStateReceived; }, true);
+            }
+        }
+        else if (loader_model->fhttp->state == SENDING || loader_model->fhttp->state == RECEIVING)
+        {
+            // continue waiting
+        }
+        else if (loader_model->fhttp->state == INACTIVE)
+        {
+            // inactive. try again
+        }
+        else if (loader_model->fhttp->state == ISSUE)
+        {
+            with_view_model(view, DataLoaderModel * model, { model->data_state = DataStateError; }, true);
+        }
+        else
+        {
+            FURI_LOG_DEV(TAG, "Unexpected state: %d lastresp: %s", loader_model->fhttp->state, loader_model->fhttp->last_response ? loader_model->fhttp->last_response : "NULL");
+            DEV_CRASH();
+        }
+    }
+    else if (current_data_state == DataStateReceived)
+    {
+        with_view_model(
+            view,
+            DataLoaderModel * model,
+            {
+                char *data_text;
+                if (model->parser == NULL)
+                {
+                    data_text = NULL;
+                    FURI_LOG_DEV(TAG, "Parser is NULL");
+                    DEV_CRASH();
+                }
+                else
+                {
+                    data_text = model->parser(model);
+                }
+                FURI_LOG_DEV(TAG, "Parsed data: %s\r\ntext: %s", model->fhttp->last_response ? model->fhttp->last_response : "NULL", data_text ? data_text : "NULL");
+                model->data_text = data_text;
+                if (data_text == NULL)
+                {
+                    model->data_state = DataStateParseError;
+                }
+                else
+                {
+                    model->data_state = DataStateParsed;
+                }
+            },
+            true);
+    }
+    else if (current_data_state == DataStateParsed)
+    {
+        with_view_model(
+            view,
+            DataLoaderModel * model,
+            {
+                if (++model->request_index < model->request_count)
+                {
+                    model->data_state = DataStateInitial;
+                }
+                else
+                {
+                    loader_widget_set_text(model->data_text != NULL ? model->data_text : "", &app->widget_result);
+                    if (model->data_text != NULL)
+                    {
+                        free(model->data_text);
+                        model->data_text = NULL;
+                    }
+                    view_set_previous_callback(widget_get_view(app->widget_result), model->back_callback);
+                    view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewWidgetResult);
+                }
+            },
+            true);
+    }
+}
+
+bool loader_custom_event_callback(void *context, uint32_t index)
+{
+    if (context == NULL)
+    {
+        FURI_LOG_E(TAG, "custom_event_callback - context is NULL");
+        DEV_CRASH();
+        return false;
+    }
+
+    switch (index)
+    {
+    case FlipSocialCustomEventProcess:
+        loader_process_callback(context);
+        return true;
+    default:
+        FURI_LOG_DEV(TAG, "custom_event_callback. Unknown index: %ld", index);
+        return false;
+    }
+}
+
+void loader_draw_callback(Canvas *canvas, void *model)
+{
+    if (!canvas || !model)
+    {
+        FURI_LOG_E(TAG, "loader_draw_callback - canvas or model is NULL");
+        return;
+    }
+
+    DataLoaderModel *data_loader_model = (DataLoaderModel *)model;
+    HTTPState http_state = data_loader_model->fhttp->state;
+    DataState data_state = data_loader_model->data_state;
+    char *title = data_loader_model->title;
+
+    canvas_set_font(canvas, FontSecondary);
+
+    if (http_state == INACTIVE)
+    {
+        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;
+    }
+
+    if (data_state == DataStateError || data_state == DataStateParseError)
+    {
+        loader_error_draw(canvas, data_loader_model);
+        return;
+    }
+
+    canvas_draw_str(canvas, 0, 7, title);
+    canvas_draw_str(canvas, 0, 17, "Loading...");
+
+    if (data_state == DataStateInitial)
+    {
+        return;
+    }
+
+    if (http_state == SENDING)
+    {
+        canvas_draw_str(canvas, 0, 27, "Fetching...");
+        return;
+    }
+
+    if (http_state == RECEIVING || data_state == DataStateRequested)
+    {
+        canvas_draw_str(canvas, 0, 27, "Receiving...");
+        return;
+    }
+
+    if (http_state == IDLE && data_state == DataStateReceived)
+    {
+        canvas_draw_str(canvas, 0, 27, "Processing...");
+        return;
+    }
+
+    if (http_state == IDLE && data_state == DataStateParsed)
+    {
+        canvas_draw_str(canvas, 0, 27, "Processed...");
+        return;
+    }
+}
+
+static void loader_timer_callback(void *context)
+{
+    if (context == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_timer_callback - context is NULL");
+        DEV_CRASH();
+        return;
+    }
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, FlipSocialCustomEventProcess);
+}
+
+static void loader_on_enter(void *context)
+{
+    if (context == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_on_enter - context is NULL");
+        DEV_CRASH();
+        return;
+    }
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    View *view = app->view_loader;
+    with_view_model(
+        view,
+        DataLoaderModel * model,
+        {
+            view_set_previous_callback(view, model->back_callback);
+            if (model->timer == NULL)
+            {
+                model->timer = furi_timer_alloc(loader_timer_callback, FuriTimerTypePeriodic, app);
+            }
+            furi_timer_start(model->timer, 250);
+        },
+        true);
+}
+
+static void loader_on_exit(void *context)
+{
+    if (context == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_on_exit - context is NULL");
+        DEV_CRASH();
+        return;
+    }
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    View *view = app->view_loader;
+    with_view_model(
+        view,
+        DataLoaderModel * model,
+        {
+            if (model->timer)
+            {
+                furi_timer_stop(model->timer);
+            }
+        },
+        false);
+}
+
+void loader_init(View *view)
+{
+    if (view == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_init - view is NULL");
+        DEV_CRASH();
+        return;
+    }
+    view_allocate_model(view, ViewModelTypeLocking, sizeof(DataLoaderModel));
+    view_set_enter_callback(view, loader_on_enter);
+    view_set_exit_callback(view, loader_on_exit);
+}
+
+void loader_free_model(View *view)
+{
+    if (view == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_free_model - view is NULL");
+        DEV_CRASH();
+        return;
+    }
+    with_view_model(
+        view,
+        DataLoaderModel * model,
+        {
+            if (model->timer)
+            {
+                furi_timer_free(model->timer);
+                model->timer = NULL;
+            }
+            if (model->parser_context)
+            {
+                // do not free the context here, it is the app context
+                // free(model->parser_context);
+                // model->parser_context = NULL;
+            }
+            if (model->fhttp)
+            {
+                flipper_http_free(model->fhttp);
+                model->fhttp = NULL;
+            }
+        },
+        false);
+}
+
+void loader_switch_to_view(FlipSocialApp *app, char *title, DataLoaderFetch fetcher, DataLoaderParser parser, size_t request_count, ViewNavigationCallback back, uint32_t view_id)
+{
+    if (app == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_switch_to_view - app is NULL");
+        DEV_CRASH();
+        return;
+    }
+
+    View *view = app->view_loader;
+    if (view == NULL)
+    {
+        FURI_LOG_E(TAG, "loader_switch_to_view - view is NULL");
+        DEV_CRASH();
+        return;
+    }
+
+    with_view_model(
+        view,
+        DataLoaderModel * model,
+        {
+            model->title = title;
+            model->fetcher = fetcher;
+            model->parser = parser;
+            model->request_index = 0;
+            model->request_count = request_count;
+            model->back_callback = back;
+            model->data_state = DataStateInitial;
+            model->data_text = NULL;
+            //
+            model->parser_context = app;
+            if (!model->fhttp)
+            {
+                model->fhttp = flipper_http_alloc();
+            }
+        },
+        true);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, view_id);
+}
+
+void loader_widget_set_text(char *message, Widget **widget)
+{
+    if (widget == NULL)
+    {
+        FURI_LOG_E(TAG, "set_widget_text - widget is NULL");
+        DEV_CRASH();
+        return;
+    }
+    if (message == NULL)
+    {
+        FURI_LOG_E(TAG, "set_widget_text - message is NULL");
+        DEV_CRASH();
+        return;
+    }
+    widget_reset(*widget);
+
+    uint32_t message_length = strlen(message); // Length of the message
+    uint32_t i = 0;                            // Index tracker
+    uint32_t formatted_index = 0;              // Tracker for where we are in the formatted message
+    char *formatted_message;                   // Buffer to hold the final formatted message
+
+    // Allocate buffer with double the message length plus one for safety
+    if (!easy_flipper_set_buffer(&formatted_message, message_length * 2 + 1))
+    {
+        return;
+    }
+
+    while (i < message_length)
+    {
+        uint32_t max_line_length = 31;                  // Maximum characters per line
+        uint32_t remaining_length = message_length - i; // Remaining characters
+        uint32_t line_length = (remaining_length < max_line_length) ? remaining_length : max_line_length;
+
+        // Check for newline character within the current segment
+        uint32_t newline_pos = i;
+        bool found_newline = false;
+        for (; newline_pos < i + line_length && newline_pos < message_length; newline_pos++)
+        {
+            if (message[newline_pos] == '\n')
+            {
+                found_newline = true;
+                break;
+            }
+        }
+
+        if (found_newline)
+        {
+            // If newline found, set line_length up to the newline
+            line_length = newline_pos - i;
+        }
+
+        // Temporary buffer to hold the current line
+        char line[32];
+        strncpy(line, message + i, line_length);
+        line[line_length] = '\0';
+
+        // If newline was found, skip it for the next iteration
+        if (found_newline)
+        {
+            i += line_length + 1; // +1 to skip the '\n' character
+        }
+        else
+        {
+            // Check if the line ends in the middle of a word and adjust accordingly
+            if (line_length == max_line_length && message[i + line_length] != '\0' && message[i + line_length] != ' ')
+            {
+                // Find the last space within the current line to avoid breaking a word
+                char *last_space = strrchr(line, ' ');
+                if (last_space != NULL)
+                {
+                    // Adjust the line_length to avoid cutting the word
+                    line_length = last_space - line;
+                    line[line_length] = '\0'; // Null-terminate at the space
+                }
+            }
+
+            // Move the index forward by the determined line_length
+            i += line_length;
+
+            // Skip any spaces at the beginning of the next line
+            while (i < message_length && message[i] == ' ')
+            {
+                i++;
+            }
+        }
+
+        // Manually copy the fixed line into the formatted_message buffer
+        for (uint32_t j = 0; j < line_length; j++)
+        {
+            formatted_message[formatted_index++] = line[j];
+        }
+
+        // Add a newline character for line spacing
+        formatted_message[formatted_index++] = '\n';
+    }
+
+    // Null-terminate the formatted_message
+    formatted_message[formatted_index] = '\0';
+
+    // Add the formatted message to the widget
+    widget_add_text_scroll_element(*widget, 0, 0, 128, 64, formatted_message);
+}

+ 39 - 0
flip_social/callback/loader.h

@@ -0,0 +1,39 @@
+#pragma once
+#include <flip_social.h>
+
+typedef enum DataState DataState;
+enum DataState
+{
+    DataStateInitial,
+    DataStateRequested,
+    DataStateReceived,
+    DataStateParsed,
+    DataStateParseError,
+    DataStateError,
+};
+
+typedef struct DataLoaderModel DataLoaderModel;
+typedef bool (*DataLoaderFetch)(DataLoaderModel *model);
+typedef char *(*DataLoaderParser)(DataLoaderModel *model);
+struct DataLoaderModel
+{
+    char *title;
+    char *data_text;
+    DataState data_state;
+    DataLoaderFetch fetcher;
+    DataLoaderParser parser;
+    void *parser_context;
+    size_t request_index;
+    size_t request_count;
+    ViewNavigationCallback back_callback;
+    FuriTimer *timer;
+    FlipperHTTP *fhttp;
+};
+bool loader_view_alloc(void *context);
+void loader_view_free(void *context);
+void loader_switch_to_view(FlipSocialApp *app, char *title, DataLoaderFetch fetcher, DataLoaderParser parser, size_t request_count, ViewNavigationCallback back, uint32_t view_id);
+void loader_draw_callback(Canvas *canvas, void *model);
+void loader_init(View *view);
+void loader_widget_set_text(char *message, Widget **widget);
+void loader_free_model(View *view);
+bool loader_custom_event_callback(void *context, uint32_t index);

+ 18 - 0
flip_social/callback/utils.h

@@ -0,0 +1,18 @@
+#pragma once
+#include <flip_social.h>
+
+// Below added by Derek Jamison
+// FURI_LOG_DEV will log only during app development. Be sure that Settings/System/Log Device is "LPUART"; so we dont use serial port.
+#ifdef DEVELOPMENT
+#define FURI_LOG_DEV(tag, format, ...) furi_log_print_format(FuriLogLevelInfo, tag, format, ##__VA_ARGS__)
+#define DEV_CRASH() furi_crash()
+#else
+#define FURI_LOG_DEV(tag, format, ...)
+#define DEV_CRASH()
+#endif
+
+typedef enum FlipSocialCustomEvent FlipSocialCustomEvent;
+enum FlipSocialCustomEvent
+{
+    FlipSocialCustomEventProcess,
+};

+ 50 - 53
flip_social/explore/flip_social_explore.c → flip_social/explore/explore.c

@@ -1,107 +1,104 @@
-#include "flip_social_explore.h"
+#include <explore/explore.h>
+#include <alloc/alloc.h>
 
-FlipSocialModel *flip_social_explore_alloc(void)
+// for now we're just listing the current users
+// as the feed is upgraded, then we can port more to the explore view
+bool explore_fetch(FlipperHTTP *fhttp)
 {
-    // Allocate memory for each username only if not already allocated
-    FlipSocialModel *explore = malloc(sizeof(FlipSocialModel));
-    if (explore == NULL)
+    if (!app_instance)
     {
-        FURI_LOG_E(TAG, "Failed to allocate memory for explore model.");
-        return NULL;
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
     }
-    return explore;
-}
 
-void flip_social_free_explore(void)
-{
-    if (flip_social_explore)
+    if (!fhttp)
     {
-        free(flip_social_explore);
-        flip_social_explore = NULL;
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
     }
-}
 
-// for now we're just listing the current users
-// as the feed is upgraded, then we can port more to the explore view
-bool flip_social_get_explore(void)
-{
-    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    // create the explore directory
+    if (!flip_social_subfolder_mkdir("explore"))
     {
-        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        FURI_LOG_E(TAG, "Failed to create explore directory");
         return false;
     }
-    char directory[128];
-    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/explore");
 
-    // Create the directory
-    Storage *storage = furi_record_open(RECORD_STORAGE);
-    storage_common_mkdir(storage, directory);
     char *keyword = !app_instance->explore_logged_in || strlen(app_instance->explore_logged_in) == 0 ? "a" : app_instance->explore_logged_in;
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
         STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/explore/%s.json",
         keyword);
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
+    fhttp->save_received_data = true;
+    alloc_headers();
     char url[256];
     snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/user/explore/%s/%d/", keyword, MAX_EXPLORE_USERS);
-    if (!flipper_http_get_request_with_headers(url, auth_headers))
+    if (!flipper_http_request(fhttp, GET, url, auth_headers, NULL))
     {
         FURI_LOG_E(TAG, "Failed to send HTTP request for explore");
-        fhttp.state = ISSUE;
+        fhttp->state = ISSUE;
         return false;
     }
-    fhttp.state = RECEIVING;
+    fhttp->state = RECEIVING;
     return true;
 }
-bool flip_social_get_explore_2(void)
+bool explore_fetch_2(FlipperHTTP *fhttp)
 {
     if (!app_instance)
     {
+        FURI_LOG_E(TAG, "App instance is NULL");
         return false;
     }
-    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    if (!fhttp)
     {
-        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+    // create the explore directory
+    if (!flip_social_subfolder_mkdir("explore"))
+    {
+        FURI_LOG_E(TAG, "Failed to create explore directory");
         return false;
     }
-    char directory[128];
-    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/explore");
 
-    // Create the directory
-    Storage *storage = furi_record_open(RECORD_STORAGE);
-    storage_common_mkdir(storage, directory);
     char *keyword = !app_instance->message_users_logged_in || strlen(app_instance->message_users_logged_in) == 0 ? "a" : app_instance->message_users_logged_in;
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
         STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/explore/%s.json",
         keyword);
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
+    fhttp->save_received_data = true;
+    alloc_headers();
     char url[256];
     snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/user/explore/%s/%d/", keyword, MAX_EXPLORE_USERS);
-    return flipper_http_get_request_with_headers(url, auth_headers);
+    return flipper_http_request(fhttp, GET, url, auth_headers, NULL);
 }
 
-bool flip_social_parse_json_explore()
+bool explore_parse_json(FlipperHTTP *fhttp)
 {
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
     // load the received data from the saved file
-    FuriString *user_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *user_data = flipper_http_load_from_file(fhttp->file_path);
     if (user_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return false;
     }
 
-    flipper_http_deinit();
-
     // Allocate memory for each username only if not already allocated
-    flip_social_explore = flip_social_explore_alloc();
+    flip_social_explore = alloc_explore();
     if (flip_social_explore == NULL)
     {
         FURI_LOG_E(TAG, "Failed to allocate memory for explore usernames.");
@@ -124,7 +121,7 @@ bool flip_social_parse_json_explore()
             break;
         }
         snprintf(flip_social_explore->usernames[i], MAX_USER_LENGTH, "%s", furi_string_get_cstr(username));
-        submenu_add_item(app_instance->submenu, flip_social_explore->usernames[i], FlipSocialSubmenuExploreIndexStartIndex + i, flip_social_callback_submenu_choices, app_instance);
+        submenu_add_item(app_instance->submenu, flip_social_explore->usernames[i], FlipSocialSubmenuExploreIndexStartIndex + i, callback_submenu_choices, app_instance);
         flip_social_explore->count++;
         furi_string_free(username);
     }

+ 7 - 0
flip_social/explore/explore.h

@@ -0,0 +1,7 @@
+#ifndef FLIP_SOCIAL_EXPLORE_H
+#define FLIP_SOCIAL_EXPLORE_H
+#include "flip_social.h"
+bool explore_fetch(FlipperHTTP *fhttp);
+bool explore_fetch_2(FlipperHTTP *fhttp);
+bool explore_parse_json(FlipperHTTP *fhttp);
+#endif

+ 0 - 10
flip_social/explore/flip_social_explore.h

@@ -1,10 +0,0 @@
-#ifndef FLIP_SOCIAL_EXPLORE_H
-#define FLIP_SOCIAL_EXPLORE_H
-#include "flip_social.h"
-#include <callback/flip_social_callback.h>
-FlipSocialModel *flip_social_explore_alloc();
-void flip_social_free_explore();
-bool flip_social_get_explore();
-bool flip_social_get_explore_2(void);
-bool flip_social_parse_json_explore();
-#endif

+ 61 - 34
flip_social/feed/flip_social_feed.c → flip_social/feed/feed.c

@@ -1,15 +1,17 @@
-#include "flip_social_feed.h"
+#include <feed/feed.h>
+#include <flip_storage/flip_social_storage.h>
+#include <alloc/alloc.h>
 
-bool flip_social_get_feed(bool alloc_http, int series_index)
+bool feed_fetch(FlipperHTTP *fhttp, int series_index)
 {
     if (!app_instance)
     {
         FURI_LOG_E(TAG, "FlipSocialApp is NULL");
         return false;
     }
-    if (alloc_http && !flipper_http_init(flipper_http_rx_callback, app_instance))
+    if (!fhttp)
     {
-        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
         return false;
     }
     // Get the feed from the server
@@ -18,13 +20,19 @@ bool flip_social_get_feed(bool alloc_http, int series_index)
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
+    // create the feed directory
+    if (!flip_social_subfolder_mkdir("feed"))
+    {
+        FURI_LOG_E(TAG, "Failed to create feed directory");
+        return false;
+    }
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed.json");
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed/feed.json");
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
+    fhttp->save_received_data = true;
+    alloc_headers();
     char command[96];
     if (strstr(flip_social_feed_type[flip_social_feed_type_index], "Global"))
     {
@@ -34,27 +42,30 @@ bool flip_social_get_feed(bool alloc_http, int series_index)
     {
         snprintf(command, 96, "https://www.jblanked.com/flipper/api/feed/%d/%s/%d/max/friends/series/", MAX_FEED_ITEMS, app_instance->login_username_logged_out, series_index);
     }
-    if (!flipper_http_get_request_with_headers(command, auth_headers))
+    if (!flipper_http_request(fhttp, GET, command, auth_headers, NULL))
     {
         FURI_LOG_E(TAG, "Failed to send HTTP request for feed");
-        fhttp.state = ISSUE;
+        fhttp->state = ISSUE;
         return false;
     }
-    fhttp.state = RECEIVING;
+    fhttp->state = RECEIVING;
     return true;
 }
 
-FlipSocialFeedMini *flip_social_parse_json_feed()
+FlipSocialFeedMini *feed_parse_json(FlipperHTTP *fhttp)
 {
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return NULL;
+    }
     // load the received data from the saved file
-    FuriString *feed_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *feed_data = flipper_http_load_from_file(fhttp->file_path);
     if (feed_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return NULL;
     }
-    flipper_http_deinit();
 
     FlipSocialFeedMini *feed_info = (FlipSocialFeedMini *)malloc(sizeof(FlipSocialFeedMini));
     if (!feed_info)
@@ -81,7 +92,8 @@ FlipSocialFeedMini *flip_social_parse_json_feed()
         {
             FURI_LOG_E(TAG, "Failed to parse item fields.");
             furi_string_free(item);
-            furi_string_free(id);
+            if (id)
+                furi_string_free(id);
             continue;
         }
         if (!flip_social_save_post(furi_string_get_cstr(id), furi_string_get_cstr(item)))
@@ -107,7 +119,7 @@ FlipSocialFeedMini *flip_social_parse_json_feed()
     return feed_info;
 }
 
-bool flip_social_load_feed_post(int post_id)
+bool feed_load_post(int post_id)
 {
     char file_path[128];
     snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed/feed_post_%d.json", post_id);
@@ -148,11 +160,16 @@ bool flip_social_load_feed_post(int post_id)
     if (username == NULL || message == NULL || flipped == NULL || flips == NULL || date_created == NULL)
     {
         FURI_LOG_E(TAG, "Failed to parse item fields.");
-        furi_string_free(username);
-        furi_string_free(message);
-        furi_string_free(flipped);
-        furi_string_free(flips);
-        furi_string_free(date_created);
+        if (username)
+            furi_string_free(username);
+        if (message)
+            furi_string_free(message);
+        if (flipped)
+            furi_string_free(flipped);
+        if (flips)
+            furi_string_free(flips);
+        if (date_created)
+            furi_string_free(date_created);
         furi_string_free(feed_data);
         return false;
     }
@@ -177,9 +194,19 @@ bool flip_social_load_feed_post(int post_id)
     return true;
 }
 
-bool flip_social_load_initial_feed(bool alloc_http, int series_index)
+bool feed_load_initial_feed(FlipperHTTP *fhttp, int series_index)
 {
-    if (fhttp.state == INACTIVE)
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
+        return false;
+    }
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+    if (fhttp->state == INACTIVE)
     {
         FURI_LOG_E(TAG, "HTTP state is INACTIVE");
         return false;
@@ -194,29 +221,29 @@ bool flip_social_load_initial_feed(bool alloc_http, int series_index)
     }
     view_dispatcher_add_view(app_instance->view_dispatcher, loading_view_id, loading_get_view(loading));
     view_dispatcher_switch_to_view(app_instance->view_dispatcher, loading_view_id);
-    if (flip_social_get_feed(alloc_http, series_index)) // start the async request
+    if (feed_fetch(fhttp, series_index)) // start the async request
     {
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
+        furi_timer_start(fhttp->get_timeout_timer, TIMEOUT_DURATION_TICKS);
+        fhttp->state = RECEIVING;
     }
     else
     {
         FURI_LOG_E(HTTP_TAG, "Failed to send request");
-        fhttp.state = ISSUE;
+        fhttp->state = ISSUE;
         view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
         view_dispatcher_remove_view(app_instance->view_dispatcher, loading_view_id);
         loading_free(loading);
         return false;
     }
-    while (fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0)
+    while (fhttp->state == RECEIVING && furi_timer_is_running(fhttp->get_timeout_timer) > 0)
     {
         // Wait for the request to be received
         furi_delay_ms(100);
     }
-    furi_timer_stop(fhttp.get_timeout_timer);
+    furi_timer_stop(fhttp->get_timeout_timer);
 
     // load feed info
-    flip_feed_info = flip_social_parse_json_feed();
+    flip_feed_info = feed_parse_json(fhttp);
     if (!flip_feed_info || flip_feed_info->count < 1)
     {
         FURI_LOG_E(TAG, "Failed to parse JSON feed");
@@ -227,7 +254,7 @@ bool flip_social_load_initial_feed(bool alloc_http, int series_index)
     }
 
     // load the current feed post
-    if (!flip_social_load_feed_post(flip_feed_info->ids[flip_feed_info->index]))
+    if (!feed_load_post(flip_feed_info->ids[flip_feed_info->index]))
     {
         FURI_LOG_E(TAG, "Failed to load feed post");
         view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
@@ -235,7 +262,7 @@ bool flip_social_load_initial_feed(bool alloc_http, int series_index)
         loading_free(loading);
         return false;
     }
-    if (!feed_view_alloc())
+    if (!alloc_feed_view())
     {
         FURI_LOG_E(TAG, "Failed to allocate feed dialog");
         view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);

+ 9 - 0
flip_social/feed/feed.h

@@ -0,0 +1,9 @@
+#ifndef FLIP_SOCIAL_FEED_H
+#define FLIP_SOCIAL_FEED_H
+#include "flip_social.h"
+
+bool feed_fetch(FlipperHTTP *fhttp, int series_index);
+FlipSocialFeedMini *feed_parse_json(FlipperHTTP *fhttp);
+bool feed_load_post(int post_id);
+bool feed_load_initial_feed(FlipperHTTP *fhttp, int series_index);
+#endif

+ 0 - 11
flip_social/feed/flip_social_feed.h

@@ -1,11 +0,0 @@
-#ifndef FLIP_SOCIAL_FEED_H
-#define FLIP_SOCIAL_FEED_H
-#include "flip_social.h"
-#include <callback/flip_social_callback.h>
-#include <flip_storage/flip_social_storage.h>
-
-bool flip_social_get_feed(bool alloc_http, int series_index);
-bool flip_social_load_feed_post(int post_id);
-bool flip_social_load_initial_feed(bool alloc_http, int series_index);
-FlipSocialFeedMini *flip_social_parse_json_feed();
-#endif

+ 15 - 126
flip_social/flip_social.c

@@ -21,135 +21,24 @@ char auth_headers[256] = {0};
 char *flip_social_feed_type[] = {"Global", "Friends"};
 uint8_t flip_social_feed_type_index = 0;
 char *flip_social_notification_type[] = {"OFF", "ON"};
-uint8_t flip_social_notification_type_index = 0;
+uint8_t flip_social_notification_type_index = 1;
 
-void flip_social_loader_free_model(View *view);
+bool went_to_friends = false;
+Loading *loading_global = NULL;
 
-/**
- * @brief Function to free the resources used by FlipSocialApp.
- * @details Cleans up all allocated resources before exiting the application.
- * @param app The FlipSocialApp object to free.
- * @return void
- */
-void flip_social_app_free(FlipSocialApp *app)
+bool flip_social_subfolder_mkdir(char *folder_name)
 {
-    if (!app)
+    if (!folder_name || strlen(folder_name) == 0)
     {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
+        FURI_LOG_E(TAG, "Folder name is NULL/empty.");
+        return false;
     }
-    if (!app->view_dispatcher)
-    {
-        FURI_LOG_E(TAG, "ViewDispatcher is NULL");
-        return;
-    }
-
-    // Free Submenu(s)
-    if (app->submenu_logged_out)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
-        submenu_free(app->submenu_logged_out);
-    }
-    if (app->submenu_logged_in)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-        submenu_free(app->submenu_logged_in);
-    }
-    //
-
-    // Free Widget(s)
-    if (app->widget_result)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewWidgetResult);
-        widget_free(app->widget_result);
-    }
-
-    // Free View(s)
-    if (app->view_loader)
-    {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoader);
-        flip_social_loader_free_model(app->view_loader);
-        view_free(app->view_loader);
-    }
-
-    if (app->view_dispatcher)
-        view_dispatcher_free(app->view_dispatcher);
-
-    // Free the app structure members
-    if (app->wifi_ssid_logged_out)
-        free(app->wifi_ssid_logged_out);
-    if (app->wifi_ssid_logged_out_temp_buffer)
-        free(app->wifi_ssid_logged_out_temp_buffer);
-    if (app->wifi_password_logged_out)
-        free(app->wifi_password_logged_out);
-    if (app->wifi_password_logged_out_temp_buffer)
-        free(app->wifi_password_logged_out_temp_buffer);
-    if (app->login_username_logged_out)
-        free(app->login_username_logged_out);
-    if (app->login_username_logged_out_temp_buffer)
-        free(app->login_username_logged_out_temp_buffer);
-    if (app->login_password_logged_out)
-        free(app->login_password_logged_out);
-    if (app->login_password_logged_out_temp_buffer)
-        free(app->login_password_logged_out_temp_buffer);
-    if (app->register_username_logged_out)
-        free(app->register_username_logged_out);
-    if (app->register_username_logged_out_temp_buffer)
-        free(app->register_username_logged_out_temp_buffer);
-    if (app->register_password_logged_out)
-        free(app->register_password_logged_out);
-    if (app->register_password_logged_out_temp_buffer)
-        free(app->register_password_logged_out_temp_buffer);
-    if (app->register_password_2_logged_out)
-        free(app->register_password_2_logged_out);
-    if (app->register_password_2_logged_out_temp_buffer)
-        free(app->register_password_2_logged_out_temp_buffer);
-    if (app->change_password_logged_in)
-        free(app->change_password_logged_in);
-    if (app->change_password_logged_in_temp_buffer)
-        free(app->change_password_logged_in_temp_buffer);
-    if (app->change_bio_logged_in)
-        free(app->change_bio_logged_in);
-    if (app->compose_pre_save_logged_in)
-        free(app->compose_pre_save_logged_in);
-    if (app->compose_pre_save_logged_in_temp_buffer)
-        free(app->compose_pre_save_logged_in_temp_buffer);
-    if (app->explore_logged_in)
-        free(app->explore_logged_in);
-    if (app->explore_logged_in_temp_buffer)
-        free(app->explore_logged_in_temp_buffer);
-    if (app->message_users_logged_in)
-        free(app->message_users_logged_in);
-    if (app->message_users_logged_in_temp_buffer)
-        free(app->message_users_logged_in_temp_buffer);
-    if (app->wifi_ssid_logged_in)
-        free(app->wifi_ssid_logged_in);
-    if (app->wifi_ssid_logged_in_temp_buffer)
-        free(app->wifi_ssid_logged_in_temp_buffer);
-    if (app->wifi_password_logged_in)
-        free(app->wifi_password_logged_in);
-    if (app->wifi_password_logged_in_temp_buffer)
-        free(app->wifi_password_logged_in_temp_buffer);
-    if (app->is_logged_in)
-        free(app->is_logged_in);
-    if (app->login_username_logged_in)
-        free(app->login_username_logged_in);
-    if (app->login_username_logged_in_temp_buffer)
-        free(app->login_username_logged_in_temp_buffer);
-    if (app->messages_new_message_logged_in)
-        free(app->messages_new_message_logged_in);
-    if (app->messages_new_message_logged_in_temp_buffer)
-        free(app->messages_new_message_logged_in_temp_buffer);
-    if (app->message_user_choice_logged_in)
-        free(app->message_user_choice_logged_in);
-    if (app->message_user_choice_logged_in_temp_buffer)
-        free(app->message_user_choice_logged_in_temp_buffer);
-    if (selected_message)
-        free(selected_message);
-    if (app->explore_user_bio)
-        free(app->explore_user_bio);
-
-    // Free the app structure
-    if (app_instance)
-        free(app_instance);
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    char directory[128];
+    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social");
+    storage_common_mkdir(storage, directory);
+    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/%s", folder_name);
+    storage_common_mkdir(storage, directory);
+    furi_record_close(RECORD_STORAGE);
+    return true;
 }

+ 16 - 4
flip_social/flip_social.h

@@ -8,16 +8,18 @@
 #include <input/input.h>
 #include <flip_social_icons.h>
 #include <font/font.h>
+#include <gui/modules/empty_screen.h>
 
 #define TAG "FlipSocial"
-#define VERSION_TAG TAG " v1.0.4"
+#define VERSION "1.1"
+#define VERSION_TAG TAG " v" VERSION
 
 #define MAX_PRE_SAVED_MESSAGES 20 // Maximum number of pre-saved messages
 #define MAX_MESSAGE_LENGTH 100    // Maximum length of a message in the feed
 #define MAX_EXPLORE_USERS 50      // Maximum number of users to explore
 #define MAX_USER_LENGTH 32        // Maximum length of a username
 #define MAX_FRIENDS 50            // Maximum number of friends
-#define MAX_FEED_ITEMS 20         // Maximum number of feed items
+#define MAX_FEED_ITEMS 12         // Maximum number of feed items
 #define MAX_LINE_LENGTH 27
 #define MAX_MESSAGE_USERS 40 // Maximum number of users to display in the submenu
 #define MAX_MESSAGES 20      // Maximum number of meesages between each user
@@ -170,11 +172,16 @@ typedef enum
     FlipSocialViewVariableItemList,
     //
     FlipSocialViewSubmenu,
+    //
+    FlipSocialViewEmpty,
 } FlipSocialView;
 
+#define BUFFER_VIEW FlipSocialViewEmpty
+
 // Define the application structure
 typedef struct
 {
+    FlipperHTTP *fhttp; // The HTTP client
     View *view_loader;
     Widget *widget_result;
     //
@@ -298,9 +305,9 @@ typedef struct
     View *view_feed;
 
     char *explore_user_bio; // Store the bio of the selected user
-} FlipSocialApp;
 
-void flip_social_app_free(FlipSocialApp *app);
+    EmptyScreen *empty_screen; // The empty screen
+} FlipSocialApp;
 
 extern FlipSocialModel *flip_social_friends;        // Store the friends
 extern FlipSocialModel2 *flip_social_message_users; // Store the users that have sent messages to the logged in user
@@ -325,4 +332,9 @@ extern uint8_t flip_social_feed_type_index;
 //
 extern char *flip_social_notification_type[];
 extern uint8_t flip_social_notification_type_index;
+//
+extern bool went_to_friends;
+extern Loading *loading_global;
+
+bool flip_social_subfolder_mkdir(char *folder_name);
 #endif

+ 1 - 1
flip_social/flip_storage/flip_social_storage.c

@@ -489,7 +489,7 @@ bool load_char(
     {
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
-        return NULL; // Return false if the file does not exist
+        return false;
     }
 
     // Read data into the buffer

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 789 - 687
flip_social/flipper_http/flipper_http.c


+ 161 - 303
flip_social/flipper_http/flipper_http.h

@@ -1,6 +1,8 @@
-// flipper_http.h
-#ifndef FLIPPER_HTTP_H
-#define FLIPPER_HTTP_H
+// Description: Flipper HTTP API (For use with Flipper Zero and the FlipperHTTP flash: https://github.com/jblanked/FlipperHTTP)
+// License: MIT
+// Author: JBlanked
+// File: flipper_http.h
+#pragma once
 
 #include <gui/gui.h>
 #include <gui/view.h>
@@ -13,390 +15,246 @@
 #include <storage/storage.h>
 #include <momentum/settings.h>
 
-// STORAGE_EXT_PATH_PREFIX is defined in the Furi SDK as /ext
-
-#define HTTP_TAG "FlipSocial"             // change this to your app name
-#define http_tag "flip_social"            // change this to your app id
-#define UART_CH (momentum_settings.uart_esp_channel)    // UART channel
-#define TIMEOUT_DURATION_TICKS (8 * 1000) // 8 seconds (increased for Pico W)
-#define BAUDRATE (115200)                 // UART baudrate
-#define RX_BUF_SIZE 2048                  // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE 7000          // UART RX line buffer size (increase for large responses)
-#define MAX_FILE_SHOW 7000                // Maximum data from file to show
-#define FILE_BUFFER_SIZE 512              // File buffer size
+#define HTTP_TAG               "FlipSocial" // change this to your app name
+#define http_tag               "flip_social" // change this to your app id
+#define UART_CH                (momentum_settings.uart_esp_channel) // UART channel
+#define TIMEOUT_DURATION_TICKS (7 * 1000) // 7 seconds
+#define BAUDRATE               (115200) // UART baudrate
+#define RX_BUF_SIZE            2048 // UART RX buffer size
+#define RX_LINE_BUFFER_SIZE    2048 // UART RX line buffer size (increase for large responses)
+#define MAX_FILE_SHOW          2048 // Maximum data from file to show
+#define FILE_BUFFER_SIZE       512 // File buffer size
 
 // Forward declaration for callback
-typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
+typedef void (*FlipperHTTP_Callback)(const char* line, void* context);
 
 // State variable to track the UART state
-typedef enum
-{
-    INACTIVE,  // Inactive state
-    IDLE,      // Default state
+typedef enum {
+    INACTIVE, // Inactive state
+    IDLE, // Default state
     RECEIVING, // Receiving data
-    SENDING,   // Sending data
-    ISSUE,     // Issue with connection
-} SerialState;
+    SENDING, // Sending data
+    ISSUE, // Issue with connection
+} HTTPState;
 
 // Event Flags for UART Worker Thread
-typedef enum
-{
+typedef enum {
     WorkerEvtStop = (1 << 0),
     WorkerEvtRxDone = (1 << 1),
 } WorkerEvtFlags;
 
+typedef enum {
+    GET, // GET request
+    POST, // POST request
+    PUT, // PUT request
+    DELETE, // DELETE request
+    //
+    BYTES, // Stream bytes to file
+    BYTES_POST, // Stream bytes to file after a POST request
+} HTTPMethod;
+
+typedef enum {
+    HTTP_CMD_WIFI_CONNECT,
+    HTTP_CMD_WIFI_DISCONNECT,
+    HTTP_CMD_IP_ADDRESS,
+    HTTP_CMD_IP_WIFI,
+    HTTP_CMD_SCAN,
+    HTTP_CMD_LIST_COMMANDS,
+    HTTP_CMD_LED_ON,
+    HTTP_CMD_LED_OFF,
+    HTTP_CMD_PING,
+    HTTP_CMD_REBOOT
+} HTTPCommand; // list of non-input commands
+
 // FlipperHTTP Structure
-typedef struct
-{
-    FuriStreamBuffer *flipper_http_stream;  // Stream buffer for UART communication
-    FuriHalSerialHandle *serial_handle;     // Serial handle for UART communication
-    FuriThread *rx_thread;                  // Worker thread for UART
-    FuriThreadId rx_thread_id;              // Worker thread ID
+typedef struct {
+    FuriStreamBuffer* flipper_http_stream; // Stream buffer for UART communication
+    FuriHalSerialHandle* serial_handle; // Serial handle for UART communication
+    FuriThread* rx_thread; // Worker thread for UART
+    FuriThreadId rx_thread_id; // Worker thread ID
     FlipperHTTP_Callback handle_rx_line_cb; // Callback for received lines
-    void *callback_context;                 // Context for the callback
-    SerialState state;                      // State of the UART
-
-    // variable to store the last received data from the UART
-    char *last_response;
+    void* callback_context; // Context for the callback
+    HTTPState state; // State of the UART
+    HTTPMethod method; // HTTP method
+    char* last_response; // variable to store the last received data from the UART
     char file_path[256]; // Path to save the received data
-
-    // Timer-related members
-    FuriTimer *get_timeout_timer; // Timer for HTTP request timeout
-
-    bool started_receiving_get; // Indicates if a GET request has started
-    bool just_started_get;      // Indicates if GET data reception has just started
-
-    bool started_receiving_post; // Indicates if a POST request has started
-    bool just_started_post;      // Indicates if POST data reception has just started
-
-    bool started_receiving_put; // Indicates if a PUT request has started
-    bool just_started_put;      // Indicates if PUT data reception has just started
-
-    bool started_receiving_delete; // Indicates if a DELETE request has started
-    bool just_started_delete;      // Indicates if DELETE data reception has just started
-
-    // Buffer to hold the raw bytes received from the UART
-    uint8_t *received_bytes;
-    size_t received_bytes_len; // Length of the received bytes
-    bool is_bytes_request;     // Flag to indicate if the request is for bytes
-    bool save_bytes;           // Flag to save the received data to a file
-    bool save_received_data;   // Flag to save the received data to a file
-
+    FuriTimer* get_timeout_timer; // Timer for HTTP request timeout
+    bool started_receiving; // Indicates if a request has started
+    bool just_started; // Indicates if data reception has just started
+    bool is_bytes_request; // Flag to indicate if the request is for bytes
+    bool save_bytes; // Flag to save the received data to a file
+    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;
+    size_t bytes_received; // Number of bytes received
+    char rx_line_buffer[RX_LINE_BUFFER_SIZE]; // Buffer for received lines
+    uint8_t file_buffer[FILE_BUFFER_SIZE]; // Buffer for file data
+    size_t file_buffer_len; // Length of the file buffer
+    size_t content_length; // Length of the content received
+    int status_code; // HTTP status code
 } FlipperHTTP;
 
-extern FlipperHTTP fhttp;
-
-// fhttp.last_response holds the last received data from the UART
-
-// Function to append received data to file
-// make sure to initialize the file path before calling this function
-bool flipper_http_append_to_file(
-    const void *data,
-    size_t data_size,
-    bool start_new_file,
-    char *file_path);
-
-FuriString *flipper_http_load_from_file(char *file_path);
-
-// UART worker thread
-/**
- * @brief      Worker thread to handle UART data asynchronously.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-// UART worker thread
-int32_t flipper_http_worker(void *context);
-
-// Timer callback function
-/**
- * @brief      Callback function for the GET timeout timer.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will be called when the GET request times out.
- */
-void get_timeout_timer_callback(void *context);
-
-// UART RX Handler Callback (Interrupt Context)
-/**
- * @brief      A private callback function to handle received data asynchronously.
- * @return     void
- * @param      handle    The UART handle.
- * @param      event     The event type.
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-void _flipper_http_rx_callback(
-    FuriHalSerialHandle *handle,
-    FuriHalSerialRxEvent event,
-    void *context);
-
-// UART initialization function
 /**
  * @brief      Initialize UART.
- * @return     true if the UART was initialized successfully, false otherwise.
- * @param      callback  The callback function to handle received data (ex. flipper_http_rx_callback).
- * @param      context   The context to pass to the callback.
+ * @return     FlipperHTTP context if the UART was initialized successfully, NULL otherwise.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
+FlipperHTTP* flipper_http_alloc();
 
-// Deinitialize UART
 /**
  * @brief      Deinitialize UART.
  * @return     void
+ * @param fhttp The FlipperHTTP context
  * @note       This function will stop the asynchronous RX, release the serial handle, and free the resources.
  */
-void flipper_http_deinit();
+void flipper_http_free(FlipperHTTP* fhttp);
 
-// Function to send data over UART with newline termination
 /**
- * @brief      Send data over UART with newline termination.
- * @return     true if the data was sent successfully, false otherwise.
- * @param      data  The data to send over UART.
- * @note       The data will be sent over UART with a newline character appended.
+ * @brief      Append received data to a file.
+ * @return     true if the data was appended successfully, false otherwise.
+ * @param      data        The data to append to the file.
+ * @param      data_size   The size of the data to append.
+ * @param      start_new_file  Flag to indicate if a new file should be created.
+ * @param      file_path   The path to the file.
+ * @note       Make sure to initialize the file path before calling this function.
  */
-bool flipper_http_send_data(const char *data);
-
-// Function to send a PING request
-/**
- * @brief      Send a PING request to check if the Wifi Dev Board is connected.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- * @note       This is best used to check if the Wifi Dev Board is connected.
- * @note       The state will remain INACTIVE until a PONG is received.
- */
-bool flipper_http_ping();
+bool flipper_http_append_to_file(
+    const void* data,
+    size_t data_size,
+    bool start_new_file,
+    char* file_path);
 
-// Function to list available commands
 /**
- * @brief      Send a command to list available commands.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Load data from a file.
+ * @return     The loaded data as a FuriString.
+ * @param      file_path The path to the file to load.
  */
-bool flipper_http_list_commands();
+FuriString* flipper_http_load_from_file(char* file_path);
 
-// Function to turn on the LED
 /**
- * @brief      Allow the LED to display while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Load data from a file with a size limit.
+ * @return     The loaded data as a FuriString.
+ * @param      file_path The path to the file to load.
+ * @param      limit     The size limit for loading data.
  */
-bool flipper_http_led_on();
+FuriString* flipper_http_load_from_file_with_limit(char* file_path, size_t limit);
 
-// Function to turn off the LED
 /**
- * @brief      Disable the LED from displaying while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief Perform a task while displaying a loading screen
+ * @param fhttp The FlipperHTTP context
+ * @param http_request The function to send the request
+ * @param parse_response The function to parse the response
+ * @param success_view_id The view ID to switch to on success
+ * @param failure_view_id The view ID to switch to on failure
+ * @param view_dispatcher The view dispatcher to use
+ * @return
  */
-bool flipper_http_led_off();
+void flipper_http_loading_task(
+    FlipperHTTP* fhttp,
+    bool (*http_request)(void),
+    bool (*parse_response)(void),
+    uint32_t success_view_id,
+    uint32_t failure_view_id,
+    ViewDispatcher** view_dispatcher);
 
-// Function to parse JSON data
 /**
  * @brief      Parse JSON data.
  * @return     true if the JSON data was parsed successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
  * @param      key       The key to parse from the JSON data.
  * @param      json_data The JSON data to parse.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_parse_json(const char *key, const char *json_data);
+bool flipper_http_parse_json(FlipperHTTP* fhttp, const char* key, const char* json_data);
 
-// Function to parse JSON array data
 /**
  * @brief      Parse JSON array data.
  * @return     true if the JSON array data was parsed successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
  * @param      key       The key to parse from the JSON array data.
  * @param      index     The index to parse from the JSON array data.
  * @param      json_data The JSON array data to parse.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
-
-// Function to scan for WiFi networks
-/**
- * @brief      Send a command to scan for WiFi networks.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_scan_wifi();
-
-// Function to save WiFi settings (returns true if successful)
-/**
- * @brief      Send a command to save WiFi settings.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_save_wifi(const char *ssid, const char *password);
+bool flipper_http_parse_json_array(
+    FlipperHTTP* fhttp,
+    const char* key,
+    int index,
+    const char* json_data);
 
-// Function to get IP address of WiFi Devboard
 /**
- * @brief      Send a command to get the IP address of the WiFi Devboard
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_address();
-
-// Function to get IP address of the connected WiFi network
-/**
- * @brief      Send a command to get the IP address of the connected WiFi network.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_wifi();
-
-// Function to disconnect from WiFi (returns true if successful)
-/**
- * @brief      Send a command to disconnect from WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_disconnect_wifi();
-
-// Function to connect to WiFi (returns true if successful)
-/**
- * @brief      Send a command to connect to WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_connect_wifi();
-
-// Function to send a GET request
-/**
- * @brief      Send a GET request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief Process requests and parse JSON data asynchronously
+ * @param fhttp The FlipperHTTP context
+ * @param http_request The function to send the request
+ * @param parse_json The function to parse the JSON
+ * @return true if successful, false otherwise
  */
-bool flipper_http_get_request(const char *url);
+bool flipper_http_process_response_async(
+    FlipperHTTP* fhttp,
+    bool (*http_request)(void),
+    bool (*parse_json)(void));
 
-// Function to send a GET request with headers
 /**
- * @brief      Send a GET request to the specified URL.
+ * @brief      Send a request to the specified URL.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
+ * @param      fhttp The FlipperHTTP context
+ * @param      method The HTTP method to use.
+ * @param      url  The URL to send the request to.
+ * @param      headers  The headers to send with the request.
+ * @param      payload  The data to send with the request.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_get_request_with_headers(const char *url, const char *headers);
+bool flipper_http_request(
+    FlipperHTTP* fhttp,
+    HTTPMethod method,
+    const char* url,
+    const char* headers,
+    const char* payload);
 
-// Function to send a GET request with headers and return bytes
 /**
- * @brief      Send a GET request to the specified URL.
+ * @brief      Send a command to save WiFi settings.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
+ * @param fhttp The FlipperHTTP context
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_get_request_bytes(const char *url, const char *headers);
+bool flipper_http_save_wifi(FlipperHTTP* fhttp, const char* ssid, const char* password);
 
-// Function to send a POST request with headers
 /**
- * @brief      Send a POST request to the specified URL.
+ * @brief      Send a command.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      data  The data to send with the POST request.
+ * @param      fhttp The FlipperHTTP context
+ * @param      command The command to send.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_post_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
+bool flipper_http_send_command(FlipperHTTP* fhttp, HTTPCommand command);
 
-// Function to send a POST request with headers and return bytes
 /**
- * @brief      Send a POST request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      payload  The data to send with the POST request.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Send data over UART with newline termination.
+ * @return     true if the data was sent successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @param      data  The data to send over UART.
+ * @note       The data will be sent over UART with a newline character appended.
  */
-bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
+bool flipper_http_send_data(FlipperHTTP* fhttp, const char* data);
 
-// Function to send a PUT request with headers
 /**
- * @brief      Send a PUT request to the specified URL.
+ * @brief      Send a request to the specified URL to start a WebSocket connection.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the PUT request to.
- * @param      headers  The headers to send with the PUT request.
- * @param      data  The data to send with the PUT request.
+ * @param fhttp The FlipperHTTP context
+ * @param      url  The URL to send the WebSocket request to.
+ * @param port The port to connect to
+ * @param headers The headers to send with the WebSocket request
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_put_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
+bool flipper_http_websocket_start(
+    FlipperHTTP* fhttp,
+    const char* url,
+    uint16_t port,
+    const char* headers);
 
-// Function to send a DELETE request with headers
 /**
- * @brief      Send a DELETE request to the specified URL.
+ * @brief      Send a request to stop the WebSocket connection.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the DELETE request to.
- * @param      headers  The headers to send with the DELETE request.
- * @param      data  The data to send with the DELETE request.
+ * @param fhttp The FlipperHTTP context
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_delete_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
-
-// Function to handle received data asynchronously
-/**
- * @brief      Callback function to handle received data asynchronously.
- * @return     void
- * @param      line     The received line.
- * @param      context  The context passed to the callback.
- * @note       The received data will be handled asynchronously via the callback and handles the state of the UART.
- */
-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
- * @param parse_json The function to parse the JSON
- * @return true if successful, false otherwise
- */
-bool flipper_http_process_response_async(bool (*http_request)(void), bool (*parse_json)(void));
-bool flipper_http_process_response_async_2(bool (*http_request)(void), int (*parse_json)(void));
-
-/**
- * @brief Perform a task while displaying a loading screen
- * @param http_request The function to send the request
- * @param parse_response The function to parse the response
- * @param success_view_id The view ID to switch to on success
- * @param failure_view_id The view ID to switch to on failure
- * @param view_dispatcher The view dispatcher to use
- * @return
- */
-void flipper_http_loading_task(bool (*http_request)(void),
-                               bool (*parse_response)(void),
-                               uint32_t success_view_id,
-                               uint32_t failure_view_id,
-                               ViewDispatcher **view_dispatcher);
-
-/**
- * @brief Perform a task while displaying a loading screen
- * @param http_request The function to send the request
- * @param parse_response The function to parse the response
- * @param success_view_id The view ID to switch to on success
- * @param failure_view_id The view ID to switch to on failure
- * @param view_dispatcher The view dispatcher to use
- * @return
- */
-void flipper_http_loading_task_2(bool (*http_request)(void),
-                                 int (*parse_response)(void),
-                                 uint32_t success_view_id,
-                                 uint32_t failure_view_id,
-                                 ViewDispatcher **view_dispatcher);
-
-#endif // FLIPPER_HTTP_H
+bool flipper_http_websocket_stop(FlipperHTTP* fhttp);

+ 356 - 0
flip_social/free/free.c

@@ -0,0 +1,356 @@
+#include <free/free.h>
+#include <callback/loader.h>
+void free_all(bool should_free_variable_item_list, bool should_free_submenu, void *context)
+{
+    FlipSocialApp *app = (FlipSocialApp *)context;
+    furi_check(app, "FlipSocialApp is NULL");
+
+    if (should_free_submenu)
+    {
+        free_explore();
+        free_submenu();
+    }
+    if (should_free_variable_item_list)
+    {
+        free_variable_item_list();
+    }
+    free_text_input();
+    free_friends();
+    free_messages();
+    free_feed_view();
+    free_compose_dialog();
+    free_explore_dialog();
+    free_friends_dialog();
+    free_messages_dialog();
+    flip_feed_info_free();
+    free_about_widget(true);
+    free_about_widget(false);
+
+    if (went_to_friends)
+    {
+        went_to_friends = false;
+    }
+
+    // free Derek's loader
+    loader_view_free(app);
+
+    // free flipper_http
+    free_flipper_http();
+
+    // free global loading
+    if (loading_global)
+    {
+        loading_free(loading_global);
+        loading_global = NULL;
+    }
+}
+void free_text_input()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->text_input)
+    {
+        uart_text_input_free(app_instance->text_input);
+        app_instance->text_input = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewTextInput);
+    }
+}
+void free_explore_dialog()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->dialog_explore)
+    {
+        dialog_ex_free(app_instance->dialog_explore);
+        app_instance->dialog_explore = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewExploreDialog);
+    }
+}
+void free_friends_dialog()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->dialog_friends)
+    {
+        dialog_ex_free(app_instance->dialog_friends);
+        app_instance->dialog_friends = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewFriendsDialog);
+    }
+}
+void free_messages_dialog()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->dialog_messages)
+    {
+        dialog_ex_free(app_instance->dialog_messages);
+        app_instance->dialog_messages = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewMessagesDialog);
+        return;
+    }
+}
+void free_compose_dialog()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->dialog_compose)
+    {
+        dialog_ex_free(app_instance->dialog_compose);
+        app_instance->dialog_compose = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewComposeDialog);
+    }
+}
+void free_feed_view()
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->view_feed)
+    {
+        view_free(app_instance->view_feed);
+        app_instance->view_feed = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
+    }
+}
+
+void free_about_widget(bool is_logged_in)
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (is_logged_in && app_instance->widget_logged_in_about)
+    {
+        widget_free(app_instance->widget_logged_in_about);
+        app_instance->widget_logged_in_about = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSettingsAbout);
+    }
+    if (!is_logged_in && app_instance->widget_logged_out_about)
+    {
+        widget_free(app_instance->widget_logged_out_about);
+        app_instance->widget_logged_out_about = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedOutAbout);
+    }
+}
+
+void free_friends(void)
+{
+    if (!flip_social_friends)
+    {
+        return;
+    }
+    free(flip_social_friends);
+    flip_social_friends = NULL;
+}
+
+void flip_feed_info_free(void)
+{
+    if (!flip_feed_info)
+    {
+        return;
+    }
+    free(flip_feed_info);
+    flip_feed_info = NULL;
+}
+
+void free_variable_item_list(void)
+{
+    if (app_instance->variable_item_list)
+    {
+        variable_item_list_free(app_instance->variable_item_list);
+        app_instance->variable_item_list = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewVariableItemList);
+    }
+}
+
+void free_submenu(void)
+{
+    if (!app_instance)
+    {
+        return;
+    }
+    if (app_instance->submenu)
+    {
+        submenu_free(app_instance->submenu);
+        app_instance->submenu = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewSubmenu);
+    }
+}
+
+void free_message_users()
+{
+    if (flip_social_message_users == NULL)
+    {
+        return;
+    }
+    free(flip_social_message_users);
+    flip_social_message_users = NULL;
+}
+
+void free_messages()
+{
+    if (flip_social_messages == NULL)
+    {
+        return;
+    }
+    free(flip_social_messages);
+    flip_social_messages = NULL;
+}
+
+void free_explore(void)
+{
+    if (flip_social_explore)
+    {
+        free(flip_social_explore);
+        flip_social_explore = NULL;
+    }
+}
+
+void free_flipper_http()
+{
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
+        return;
+    }
+    if (app_instance->fhttp)
+    {
+        flipper_http_free(app_instance->fhttp);
+        app_instance->fhttp = NULL;
+    }
+}
+
+/**
+ * @brief Function to free the resources used by FlipSocialApp.
+ * @details Cleans up all allocated resources before exiting the application.
+ * @param app The FlipSocialApp object to free.
+ * @return void
+ */
+void free_flip_social_app(FlipSocialApp *app)
+{
+    if (!app)
+    {
+        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
+        return;
+    }
+    if (!app->view_dispatcher)
+    {
+        FURI_LOG_E(TAG, "ViewDispatcher is NULL");
+        return;
+    }
+
+    free_all(true, true, app);
+
+    // Free Submenu(s)
+    if (app->submenu_logged_out)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
+        submenu_free(app->submenu_logged_out);
+        app->submenu_logged_out = NULL;
+    }
+    if (app->submenu_logged_in)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSubmenu);
+        submenu_free(app->submenu_logged_in);
+        app->submenu_logged_in = NULL;
+    }
+
+    // Free the app structure members
+    if (app->wifi_ssid_logged_out)
+        free(app->wifi_ssid_logged_out);
+    if (app->wifi_ssid_logged_out_temp_buffer)
+        free(app->wifi_ssid_logged_out_temp_buffer);
+    if (app->wifi_password_logged_out)
+        free(app->wifi_password_logged_out);
+    if (app->wifi_password_logged_out_temp_buffer)
+        free(app->wifi_password_logged_out_temp_buffer);
+    if (app->login_username_logged_out)
+        free(app->login_username_logged_out);
+    if (app->login_username_logged_out_temp_buffer)
+        free(app->login_username_logged_out_temp_buffer);
+    if (app->login_password_logged_out)
+        free(app->login_password_logged_out);
+    if (app->login_password_logged_out_temp_buffer)
+        free(app->login_password_logged_out_temp_buffer);
+    if (app->register_username_logged_out)
+        free(app->register_username_logged_out);
+    if (app->register_username_logged_out_temp_buffer)
+        free(app->register_username_logged_out_temp_buffer);
+    if (app->register_password_logged_out)
+        free(app->register_password_logged_out);
+    if (app->register_password_logged_out_temp_buffer)
+        free(app->register_password_logged_out_temp_buffer);
+    if (app->register_password_2_logged_out)
+        free(app->register_password_2_logged_out);
+    if (app->register_password_2_logged_out_temp_buffer)
+        free(app->register_password_2_logged_out_temp_buffer);
+    if (app->change_password_logged_in)
+        free(app->change_password_logged_in);
+    if (app->change_password_logged_in_temp_buffer)
+        free(app->change_password_logged_in_temp_buffer);
+    if (app->change_bio_logged_in)
+        free(app->change_bio_logged_in);
+    if (app->compose_pre_save_logged_in)
+        free(app->compose_pre_save_logged_in);
+    if (app->compose_pre_save_logged_in_temp_buffer)
+        free(app->compose_pre_save_logged_in_temp_buffer);
+    if (app->explore_logged_in)
+        free(app->explore_logged_in);
+    if (app->explore_logged_in_temp_buffer)
+        free(app->explore_logged_in_temp_buffer);
+    if (app->message_users_logged_in)
+        free(app->message_users_logged_in);
+    if (app->message_users_logged_in_temp_buffer)
+        free(app->message_users_logged_in_temp_buffer);
+    if (app->wifi_ssid_logged_in)
+        free(app->wifi_ssid_logged_in);
+    if (app->wifi_ssid_logged_in_temp_buffer)
+        free(app->wifi_ssid_logged_in_temp_buffer);
+    if (app->wifi_password_logged_in)
+        free(app->wifi_password_logged_in);
+    if (app->wifi_password_logged_in_temp_buffer)
+        free(app->wifi_password_logged_in_temp_buffer);
+    if (app->is_logged_in)
+        free(app->is_logged_in);
+    if (app->login_username_logged_in)
+        free(app->login_username_logged_in);
+    if (app->login_username_logged_in_temp_buffer)
+        free(app->login_username_logged_in_temp_buffer);
+    if (app->messages_new_message_logged_in)
+        free(app->messages_new_message_logged_in);
+    if (app->messages_new_message_logged_in_temp_buffer)
+        free(app->messages_new_message_logged_in_temp_buffer);
+    if (app->message_user_choice_logged_in)
+        free(app->message_user_choice_logged_in);
+    if (app->message_user_choice_logged_in_temp_buffer)
+        free(app->message_user_choice_logged_in_temp_buffer);
+    if (selected_message)
+        free(selected_message);
+    if (app->explore_user_bio)
+        free(app->explore_user_bio);
+
+    if (app->empty_screen)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewEmpty);
+        empty_screen_free(app->empty_screen);
+        app->empty_screen = NULL;
+    }
+
+    if (app->view_dispatcher)
+        view_dispatcher_free(app->view_dispatcher);
+
+    // Free the app structure
+    if (app_instance)
+        free(app_instance);
+}

+ 19 - 0
flip_social/free/free.h

@@ -0,0 +1,19 @@
+#pragma once
+#include <flip_social.h>
+void free_all(bool should_free_variable_item_list, bool should_free_submenu, void *context);
+void free_text_input();
+void free_explore_dialog();
+void free_friends_dialog();
+void free_messages_dialog();
+void free_compose_dialog();
+void free_feed_view();
+void free_about_widget(bool is_logged_in);
+void free_friends(void);
+void flip_feed_info_free(void);
+void free_variable_item_list(void);
+void free_submenu(void);
+void free_message_users();
+void free_messages();
+void free_explore();
+void free_flipper_http();
+void free_flip_social_app(FlipSocialApp *app);

+ 0 - 10
flip_social/friends/flip_social_friends.h

@@ -1,10 +0,0 @@
-#ifndef FLIP_SOCIAL_FRIENDS_H
-#define FLIP_SOCIAL_FRIENDS_H
-#include "flip_social.h"
-#include <callback/flip_social_callback.h>
-
-FlipSocialModel *flip_social_friends_alloc();
-bool flip_social_get_friends();
-bool flip_social_update_friends();
-bool flip_social_parse_json_friends();
-#endif

+ 52 - 32
flip_social/friends/flip_social_friends.c → flip_social/friends/friends.c

@@ -1,48 +1,53 @@
-#include "flip_social_friends.h"
-
-FlipSocialModel *flip_social_friends_alloc()
-{
-    // Allocate memory for each username only if not already allocated
-    FlipSocialModel *friends = malloc(sizeof(FlipSocialModel));
-    if (friends == NULL)
-    {
-        FURI_LOG_E(TAG, "Failed to allocate memory for friends usernames.");
-        return NULL;
-    }
-    return friends;
-}
+#include <friends/friends.h>
+#include <alloc/alloc.h>
 
 // for now we're just listing the current users
 // as the feed is upgraded, then we can port more to the friends view
-bool flip_social_get_friends()
+bool friends_fetch(FlipperHTTP *fhttp)
 {
     if (!app_instance)
     {
         FURI_LOG_E(TAG, "App instance is NULL");
         return false;
     }
-    // will return true unless the devboard is not connected
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+
+    // create the friends directory
+    if (!flip_social_subfolder_mkdir("friends"))
+    {
+        FURI_LOG_E(TAG, "Failed to create friends directory");
+        return false;
+    }
+
     char url[100];
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/friends.json");
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/friends/friends.json");
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
-    snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/user/friends/%s/", app_instance->login_username_logged_in);
-    if (!flipper_http_get_request_with_headers(url, auth_headers))
+    fhttp->save_received_data = true;
+    alloc_headers();
+    snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/user/friends/%s/%d/", app_instance->login_username_logged_in, MAX_FRIENDS);
+    if (!flipper_http_request(fhttp, GET, url, auth_headers, NULL))
     {
         FURI_LOG_E(TAG, "Failed to send HTTP request for friends");
-        fhttp.state = ISSUE;
+        fhttp->state = ISSUE;
         return false;
     }
-    fhttp.state = RECEIVING;
     return true;
 }
 
-bool flip_social_update_friends()
+bool friends_update()
 {
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
     if (!app_instance->submenu)
     {
         FURI_LOG_E(TAG, "Friends submenu is NULL");
@@ -58,24 +63,39 @@ bool flip_social_update_friends()
     submenu_set_header(app_instance->submenu, "Friends");
     for (int i = 0; i < flip_social_friends->count; i++)
     {
-        submenu_add_item(app_instance->submenu, flip_social_friends->usernames[i], FlipSocialSubmenuLoggedInIndexFriendsStart + i, flip_social_callback_submenu_choices, app_instance);
+        submenu_add_item(app_instance->submenu, flip_social_friends->usernames[i], FlipSocialSubmenuLoggedInIndexFriendsStart + i, callback_submenu_choices, app_instance);
     }
     return true;
 }
 
-bool flip_social_parse_json_friends()
+bool friends_parse_json(FlipperHTTP *fhttp)
 {
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
+    if (!app_instance->submenu)
+    {
+        FURI_LOG_E(TAG, "Friends submenu is NULL");
+        return false;
+    }
+
     // load the received data from the saved file
-    FuriString *friend_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *friend_data = flipper_http_load_from_file(fhttp->file_path);
     if (friend_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return false;
     }
 
     //  Allocate memory for each username only if not already allocated
-    flip_social_friends = flip_social_friends_alloc();
+    flip_social_friends = alloc_friends_model();
     if (flip_social_friends == NULL)
     {
         FURI_LOG_E(TAG, "Failed to allocate memory for friends usernames.");
@@ -101,11 +121,11 @@ bool flip_social_parse_json_friends()
             break;
         }
         snprintf(flip_social_friends->usernames[i], MAX_USER_LENGTH, "%s", furi_string_get_cstr(friend));
-        submenu_add_item(app_instance->submenu, flip_social_friends->usernames[i], FlipSocialSubmenuLoggedInIndexFriendsStart + i, flip_social_callback_submenu_choices, app_instance);
+        submenu_add_item(app_instance->submenu, flip_social_friends->usernames[i], FlipSocialSubmenuLoggedInIndexFriendsStart + i, callback_submenu_choices, app_instance);
         flip_social_friends->count++;
         furi_string_free(friend);
     }
     furi_string_free(friend_data);
-    // flipper_http_deinit();
+
     return true;
 }

+ 7 - 0
flip_social/friends/friends.h

@@ -0,0 +1,7 @@
+#ifndef FLIP_SOCIAL_FRIENDS_H
+#define FLIP_SOCIAL_FRIENDS_H
+#include "flip_social.h"
+bool friends_fetch(FlipperHTTP *fhttp);
+bool friends_update();
+bool friends_parse_json(FlipperHTTP *fhttp);
+#endif

+ 0 - 27
flip_social/messages/flip_social_messages.h

@@ -1,27 +0,0 @@
-#ifndef FLIP_SOCIAL_MESSAGES_H
-#define FLIP_SOCIAL_MESSAGES_H
-
-#include "flip_social.h"
-#include <callback/flip_social_callback.h>
-#include <explore/flip_social_explore.h>
-
-FlipSocialModel2 *flip_social_messages_alloc();
-FlipSocialMessage *flip_social_user_messages_alloc();
-void flip_social_free_message_users();
-void flip_social_free_messages();
-bool flip_social_update_messages_submenu();
-bool flip_social_update_submenu_user_choices();
-// Get all the users that have sent messages to the logged in user
-bool flip_social_get_message_users();
-// Get all the messages between the logged in user and the selected user
-bool flip_social_get_messages_with_user();
-// Parse the users that have sent messages to the logged-in user
-bool flip_social_parse_json_message_users();
-
-// Parse the users that the logged in user can message
-bool flip_social_parse_json_message_user_choices();
-
-// parse messages between the logged in user and the selected user
-bool flip_social_parse_json_messages();
-
-#endif

+ 82 - 100
flip_social/messages/flip_social_messages.c → flip_social/messages/messages.c

@@ -1,50 +1,7 @@
-#include "flip_social_messages.h"
+#include <messages/messages.h>
+#include <alloc/alloc.h>
 
-FlipSocialModel2 *flip_social_messages_alloc()
-{
-    // Allocate memory for each username only if not already allocated
-    FlipSocialModel2 *users = malloc(sizeof(FlipSocialModel2));
-    if (users == NULL)
-    {
-        FURI_LOG_E(TAG, "Failed to allocate memory for message users");
-        return NULL;
-    }
-    return users;
-}
-
-FlipSocialMessage *flip_social_user_messages_alloc()
-{
-    // Allocate memory for each username only if not already allocated
-    FlipSocialMessage *messages = malloc(sizeof(FlipSocialMessage));
-    if (messages == NULL)
-    {
-        FURI_LOG_E(TAG, "Failed to allocate memory for messages");
-        return NULL;
-    }
-    return messages;
-}
-
-void flip_social_free_message_users()
-{
-    if (flip_social_message_users == NULL)
-    {
-        return;
-    }
-    free(flip_social_message_users);
-    flip_social_message_users = NULL;
-}
-
-void flip_social_free_messages()
-{
-    if (flip_social_messages == NULL)
-    {
-        return;
-    }
-    free(flip_social_messages);
-    flip_social_messages = NULL;
-}
-
-bool flip_social_update_messages_submenu()
+bool messages_submenu_update()
 {
     if (!app_instance)
     {
@@ -63,15 +20,15 @@ bool flip_social_update_messages_submenu()
     }
     submenu_reset(app_instance->submenu);
     submenu_set_header(app_instance->submenu, "Messages");
-    submenu_add_item(app_instance->submenu, "[New Message]", FlipSocialSubmenuLoggedInIndexMessagesNewMessage, flip_social_callback_submenu_choices, app_instance);
+    submenu_add_item(app_instance->submenu, "[New Message]", FlipSocialSubmenuLoggedInIndexMessagesNewMessage, callback_submenu_choices, app_instance);
     for (int i = 0; i < flip_social_message_users->count; i++)
     {
-        submenu_add_item(app_instance->submenu, flip_social_message_users->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUsersStart + i, flip_social_callback_submenu_choices, app_instance);
+        submenu_add_item(app_instance->submenu, flip_social_message_users->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUsersStart + i, callback_submenu_choices, app_instance);
     }
     return true;
 }
 
-bool flip_social_update_submenu_user_choices()
+bool messages_update_submenu_user_choices()
 {
     if (app_instance == NULL)
     {
@@ -92,56 +49,66 @@ bool flip_social_update_submenu_user_choices()
     submenu_set_header(app_instance->submenu, "Users");
     for (int i = 0; i < flip_social_explore->count; i++)
     {
-        submenu_add_item(app_instance->submenu, flip_social_explore->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart + i, flip_social_callback_submenu_choices, app_instance);
+        submenu_add_item(app_instance->submenu, flip_social_explore->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart + i, callback_submenu_choices, app_instance);
     }
     return true;
 }
 
 // Get all the users that have sent messages to the logged in user
-bool flip_social_get_message_users()
+bool messages_get_message_users(FlipperHTTP *fhttp)
 {
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
     if (app_instance->login_username_logged_out == NULL)
     {
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
-    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    // create the messages directory
+    if (!flip_social_subfolder_mkdir("messages"))
     {
-        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        FURI_LOG_E(TAG, "Failed to create messages directory");
         return false;
     }
-    char directory[128];
-    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages");
 
-    // Create the directory
-    Storage *storage = furi_record_open(RECORD_STORAGE);
-    storage_common_mkdir(storage, directory);
     char command[128];
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
         STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages/message_users.json");
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
+    fhttp->save_received_data = true;
+    alloc_headers();
     snprintf(command, 128, "https://www.jblanked.com/flipper/api/messages/%s/get/list/%d/", app_instance->login_username_logged_out, MAX_MESSAGE_USERS);
-    if (!flipper_http_get_request_with_headers(command, auth_headers))
+    if (!flipper_http_request(fhttp, GET, command, auth_headers, NULL))
     {
         FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
-        fhttp.state = ISSUE;
-        flipper_http_deinit();
+        fhttp->state = ISSUE;
         return false;
     }
-    fhttp.state = RECEIVING;
+    fhttp->state = RECEIVING;
     return true;
 }
 
 // Get all the messages between the logged in user and the selected user
-bool flip_social_get_messages_with_user()
+bool messages_get_messages_with_user(FlipperHTTP *fhttp)
 {
-    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    if (!app_instance)
     {
-        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
         return false;
     }
     if (app_instance->login_username_logged_out == NULL)
@@ -154,48 +121,52 @@ bool flip_social_get_messages_with_user()
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
-    char directory[128];
-    snprintf(directory, sizeof(directory), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages");
 
-    // Create the directory
-    Storage *storage = furi_record_open(RECORD_STORAGE);
-    storage_common_mkdir(storage, directory);
+    // create the messages directory
+    if (!flip_social_subfolder_mkdir("messages"))
+    {
+        FURI_LOG_E(TAG, "Failed to create messages directory");
+        return false;
+    }
 
     char command[256];
     snprintf(
-        fhttp.file_path,
-        sizeof(fhttp.file_path),
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
         STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages/%s_messages.json",
         flip_social_message_users->usernames[flip_social_message_users->index]);
 
-    fhttp.save_received_data = true;
-    auth_headers_alloc();
+    fhttp->save_received_data = true;
+    alloc_headers();
     snprintf(command, sizeof(command), "https://www.jblanked.com/flipper/api/messages/%s/get/%s/%d/", app_instance->login_username_logged_out, flip_social_message_users->usernames[flip_social_message_users->index], MAX_MESSAGES);
-    if (!flipper_http_get_request_with_headers(command, auth_headers))
+    if (!flipper_http_request(fhttp, GET, command, auth_headers, NULL))
     {
         FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
-        fhttp.state = ISSUE;
+        fhttp->state = ISSUE;
         return false;
     }
-    fhttp.state = RECEIVING;
+    fhttp->state = RECEIVING;
     return true;
 }
 
 // Parse the users that have sent messages to the logged-in user
-bool flip_social_parse_json_message_users()
+bool messages_parse_json_message_users(FlipperHTTP *fhttp)
 {
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
     // load the received data from the saved file
-    FuriString *message_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *message_data = flipper_http_load_from_file(fhttp->file_path);
     if (message_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return false;
     }
-    flipper_http_deinit();
 
     // Allocate memory for each username only if not already allocated
-    flip_social_message_users = flip_social_messages_alloc();
+    flip_social_message_users = alloc_messages();
     if (flip_social_message_users == NULL)
     {
         FURI_LOG_E(TAG, "Failed to allocate memory for message users.");
@@ -219,7 +190,7 @@ bool flip_social_parse_json_message_users()
     }
 
     // Add submenu items for the users
-    flip_social_update_messages_submenu();
+    messages_submenu_update();
 
     // Free the JSON data
     furi_string_free(message_data);
@@ -227,21 +198,24 @@ bool flip_social_parse_json_message_users()
 }
 
 // Parse the users that the logged in user can message
-bool flip_social_parse_json_message_user_choices()
+bool messages_parse_json_message_user_choices(FlipperHTTP *fhttp)
 {
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+
     // load the received data from the saved file
-    FuriString *user_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *user_data = flipper_http_load_from_file(fhttp->file_path);
     if (user_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return false;
     }
 
-    flipper_http_deinit();
-
     // Allocate memory for each username only if not already allocated
-    flip_social_explore = flip_social_explore_alloc();
+    flip_social_explore = alloc_explore();
     if (flip_social_explore == NULL)
     {
         FURI_LOG_E(TAG, "Failed to allocate memory for explore usernames.");
@@ -265,7 +239,7 @@ bool flip_social_parse_json_message_user_choices()
     }
 
     // Add submenu items for the users
-    flip_social_update_submenu_user_choices();
+    messages_update_submenu_user_choices();
 
     // Free the JSON data
     furi_string_free(user_data);
@@ -273,20 +247,24 @@ bool flip_social_parse_json_message_user_choices()
 }
 
 // parse messages between the logged in user and the selected user
-bool flip_social_parse_json_messages()
+bool messages_parse_json_messages(FlipperHTTP *fhttp)
 {
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL");
+        return false;
+    }
+
     // load the received data from the saved file
-    FuriString *message_data = flipper_http_load_from_file(fhttp.file_path);
+    FuriString *message_data = flipper_http_load_from_file(fhttp->file_path);
     if (message_data == NULL)
     {
         FURI_LOG_E(TAG, "Failed to load received data from file.");
-        flipper_http_deinit();
         return false;
     }
-    flipper_http_deinit();
 
     // Allocate memory for each message only if not already allocated
-    flip_social_messages = flip_social_user_messages_alloc();
+    flip_social_messages = alloc_user_messages();
     if (!flip_social_messages)
     {
         FURI_LOG_E(TAG, "Failed to allocate memory for messages.");
@@ -314,6 +292,10 @@ bool flip_social_parse_json_messages()
         if (sender == NULL || content == NULL)
         {
             FURI_LOG_E(TAG, "Failed to parse item fields.");
+            if (sender)
+                furi_string_free(sender);
+            if (content)
+                furi_string_free(content);
             furi_string_free(item);
             continue;
         }
@@ -327,7 +309,7 @@ bool flip_social_parse_json_messages()
         furi_string_free(sender);
         furi_string_free(content);
     }
-    if (!messages_dialog_alloc(true))
+    if (!allow_messages_dialog(true))
     {
         FURI_LOG_E(TAG, "Failed to allocate and set messages dialog.");
         furi_string_free(message_data);

+ 21 - 0
flip_social/messages/messages.h

@@ -0,0 +1,21 @@
+#ifndef FLIP_SOCIAL_MESSAGES_H
+#define FLIP_SOCIAL_MESSAGES_H
+
+#include "flip_social.h"
+
+bool messages_submenu_update();
+bool messages_update_submenu_user_choices();
+// Get all the users that have sent messages to the logged in user
+bool messages_get_message_users(FlipperHTTP *fhttp);
+// Get all the messages between the logged in user and the selected user
+bool messages_get_messages_with_user(FlipperHTTP *fhttp);
+// Parse the users that have sent messages to the logged-in user
+bool messages_parse_json_message_users(FlipperHTTP *fhttp);
+
+// Parse the users that the logged in user can message
+bool messages_parse_json_message_user_choices(FlipperHTTP *fhttp);
+
+// parse messages between the logged in user and the selected user
+bool messages_parse_json_messages(FlipperHTTP *fhttp);
+
+#endif

+ 546 - 0
flip_social/update/update.c

@@ -0,0 +1,546 @@
+#include <update/update.h>
+#include <storage/storage.h>
+
+static bool update_is_str(const char *src, const char *dst) { return strcmp(src, dst) == 0; }
+static bool update_save_char(
+    const char *path_name, const char *value)
+{
+    if (!value)
+    {
+        return false;
+    }
+    // Create the directory for saving settings
+    char directory_path[256];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s", APP_ID);
+
+    // Create the directory
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, directory_path);
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data", APP_ID);
+    storage_common_mkdir(storage, directory_path);
+
+    // Open the settings file
+    File *file = storage_file_alloc(storage);
+    char file_path[256];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data/%s.txt", APP_ID, path_name);
+
+    // Open the file in write mode
+    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to open file for writing: %s", file_path);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Write the data to the file
+    size_t data_size = strlen(value) + 1; // Include null terminator
+    if (storage_file_write(file, value, data_size) != data_size)
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
+    return true;
+}
+
+static bool update_load_char(
+    const char *path_name,
+    char *value,
+    size_t value_size)
+{
+    if (!value)
+    {
+        return false;
+    }
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    File *file = storage_file_alloc(storage);
+
+    char file_path[256];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data/%s.txt", APP_ID, path_name);
+
+    // Open the file for reading
+    if (!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING))
+    {
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Read data into the buffer
+    size_t read_count = storage_file_read(file, value, value_size);
+    if (storage_file_get_error(file) != FSE_OK)
+    {
+        FURI_LOG_E(HTTP_TAG, "Error reading from file.");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Ensure null-termination
+    value[read_count - 1] = '\0';
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
+    return strlen(value) > 0;
+}
+static bool update_json_to_datetime(DateTime *rtc_time, FuriString *str)
+{
+    if (!rtc_time || !str)
+    {
+        FURI_LOG_E(TAG, "rtc_time or str is NULL");
+        return false;
+    }
+    FuriString *hour = get_json_value_furi("hour", str);
+    if (hour)
+    {
+        rtc_time->hour = atoi(furi_string_get_cstr(hour));
+        furi_string_free(hour);
+    }
+    FuriString *minute = get_json_value_furi("minute", str);
+    if (minute)
+    {
+        rtc_time->minute = atoi(furi_string_get_cstr(minute));
+        furi_string_free(minute);
+    }
+    FuriString *second = get_json_value_furi("second", str);
+    if (second)
+    {
+        rtc_time->second = atoi(furi_string_get_cstr(second));
+        furi_string_free(second);
+    }
+    FuriString *day = get_json_value_furi("day", str);
+    if (day)
+    {
+        rtc_time->day = atoi(furi_string_get_cstr(day));
+        furi_string_free(day);
+    }
+    FuriString *month = get_json_value_furi("month", str);
+    if (month)
+    {
+        rtc_time->month = atoi(furi_string_get_cstr(month));
+        furi_string_free(month);
+    }
+    FuriString *year = get_json_value_furi("year", str);
+    if (year)
+    {
+        rtc_time->year = atoi(furi_string_get_cstr(year));
+        furi_string_free(year);
+    }
+    FuriString *weekday = get_json_value_furi("weekday", str);
+    if (weekday)
+    {
+        rtc_time->weekday = atoi(furi_string_get_cstr(weekday));
+        furi_string_free(weekday);
+    }
+    return datetime_validate_datetime(rtc_time);
+}
+
+static FuriString *update_datetime_to_json(DateTime *rtc_time)
+{
+    if (!rtc_time)
+    {
+        FURI_LOG_E(TAG, "rtc_time is NULL");
+        return NULL;
+    }
+    char json[256];
+    snprintf(
+        json,
+        sizeof(json),
+        "{\"hour\":%d,\"minute\":%d,\"second\":%d,\"day\":%d,\"month\":%d,\"year\":%d,\"weekday\":%d}",
+        rtc_time->hour,
+        rtc_time->minute,
+        rtc_time->second,
+        rtc_time->day,
+        rtc_time->month,
+        rtc_time->year,
+        rtc_time->weekday);
+    return furi_string_alloc_set_str(json);
+}
+
+static bool update_save_rtc_time(DateTime *rtc_time)
+{
+    if (!rtc_time)
+    {
+        FURI_LOG_E(TAG, "rtc_time is NULL");
+        return false;
+    }
+    FuriString *json = update_datetime_to_json(rtc_time);
+    if (!json)
+    {
+        FURI_LOG_E(TAG, "Failed to convert DateTime to JSON");
+        return false;
+    }
+    update_save_char("last_checked", furi_string_get_cstr(json));
+    furi_string_free(json);
+    return true;
+}
+
+//
+// Returns true if time_current is one hour (or more) later than the stored last_checked time
+//
+static bool update_is_update_time(DateTime *time_current)
+{
+    if (!time_current)
+    {
+        FURI_LOG_E(TAG, "time_current is NULL");
+        return false;
+    }
+    char last_checked_old[128];
+    if (!update_load_char("last_checked", last_checked_old, sizeof(last_checked_old)))
+    {
+        FURI_LOG_E(TAG, "Failed to load last_checked");
+        FuriString *json = update_datetime_to_json(time_current);
+        if (json)
+        {
+            update_save_char("last_checked", furi_string_get_cstr(json));
+            furi_string_free(json);
+        }
+        return false;
+    }
+
+    DateTime last_updated_time;
+
+    FuriString *last_updated_furi = char_to_furi_string(last_checked_old);
+    if (!last_updated_furi)
+    {
+        FURI_LOG_E(TAG, "Failed to convert char to FuriString");
+        return false;
+    }
+    if (!update_json_to_datetime(&last_updated_time, last_updated_furi))
+    {
+        FURI_LOG_E(TAG, "Failed to convert JSON to DateTime");
+        furi_string_free(last_updated_furi);
+        return false;
+    }
+    furi_string_free(last_updated_furi); // Free after usage.
+
+    bool time_diff = false;
+    // If the date is different assume more than one hour has passed.
+    if (time_current->year != last_updated_time.year ||
+        time_current->month != last_updated_time.month ||
+        time_current->day != last_updated_time.day)
+    {
+        time_diff = true;
+    }
+    else
+    {
+        // For the same day, compute seconds from midnight.
+        int seconds_current = time_current->hour * 3600 + time_current->minute * 60 + time_current->second;
+        int seconds_last = last_updated_time.hour * 3600 + last_updated_time.minute * 60 + last_updated_time.second;
+        if ((seconds_current - seconds_last) >= 3600)
+        {
+            time_diff = true;
+        }
+    }
+
+    return time_diff;
+}
+
+// Sends a request to fetch the last updated date of the app.
+static bool update_last_app_update(FlipperHTTP *fhttp, bool flipper_server)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "fhttp is NULL");
+        return false;
+    }
+    char url[256];
+    if (flipper_server)
+    {
+        // make sure folder is created
+        char directory_path[256];
+        snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s", APP_ID);
+
+        // Create the directory
+        Storage *storage = furi_record_open(RECORD_STORAGE);
+        storage_common_mkdir(storage, directory_path);
+        snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data", APP_ID);
+        storage_common_mkdir(storage, directory_path);
+        snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data/last_update_request.txt", APP_ID);
+        storage_simply_remove_recursive(storage, directory_path); // ensure the file is empty
+        furi_record_close(RECORD_STORAGE);
+
+        fhttp->save_received_data = false;
+        fhttp->is_bytes_request = true;
+
+        snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/%s/data/last_update_request.txt", APP_ID);
+        snprintf(url, sizeof(url), "https://raw.githubusercontent.com/flipperdevices/flipper-application-catalog/main/applications/%s/%s/manifest.yml", APP_FOLDER, FAP_ID);
+        return flipper_http_request(fhttp, BYTES, url, "{\"Content-Type\":\"application/json\"}", NULL);
+    }
+    else
+    {
+        snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/app/last-updated/%s/", FAP_ID);
+        return flipper_http_request(fhttp, GET, url, "{\"Content-Type\":\"application/json\"}", NULL);
+    }
+}
+
+static bool parse_yaml_version(const char *yaml, char *out_version, size_t out_len)
+{
+    const char *p = strstr(yaml, "\nversion:");
+    if (!p)
+    {
+        // maybe it's the very first line
+        p = yaml;
+    }
+    else
+    {
+        // skip the “\n”
+        p++;
+    }
+    // skip the key name and colon
+    p = strstr(p, "version");
+    if (!p)
+        return false;
+    p += strlen("version");
+    // skip whitespace and colon
+    while (*p == ' ' || *p == ':')
+        p++;
+    // handle optional quote
+    bool quoted = (*p == '"');
+    if (quoted)
+        p++;
+    // copy up until end‐quote or newline/space
+    size_t i = 0;
+    while (*p && i + 1 < out_len)
+    {
+        if ((quoted && *p == '"') ||
+            (!quoted && (*p == '\n' || *p == ' ')))
+        {
+            break;
+        }
+        out_version[i++] = *p++;
+    }
+    out_version[i] = '\0';
+    return (i > 0);
+}
+
+// Parses the server response and returns true if an update is available.
+static bool update_parse_last_app_update(FlipperHTTP *fhttp, DateTime *time_current, bool flipper_server)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "fhttp is NULL");
+        return false;
+    }
+    if (fhttp->state == ISSUE)
+    {
+        FURI_LOG_E(TAG, "Failed to fetch last app update");
+        return false;
+    }
+    char version_str[32];
+    if (!flipper_server)
+    {
+        if (fhttp->last_response == NULL || strlen(fhttp->last_response) == 0)
+        {
+            FURI_LOG_E(TAG, "fhttp->last_response is NULL or empty");
+            return false;
+        }
+
+        char *app_version = get_json_value("version", fhttp->last_response);
+        if (app_version)
+        {
+            // Save the server app version: it should save something like: 0.8
+            update_save_char("server_app_version", app_version);
+            snprintf(version_str, sizeof(version_str), "%s", app_version);
+            free(app_version);
+        }
+        else
+        {
+            FURI_LOG_E(TAG, "Failed to get app version");
+            return false;
+        }
+    }
+    else
+    {
+        FuriString *manifest_data = flipper_http_load_from_file(fhttp->file_path);
+        if (!manifest_data)
+        {
+            FURI_LOG_E(TAG, "Failed to load app data");
+            return false;
+        }
+        // parse version out of the YAML
+        if (!parse_yaml_version(furi_string_get_cstr(manifest_data), version_str, sizeof(version_str)))
+        {
+            FURI_LOG_E(TAG, "Failed to parse version from YAML manifest");
+            return false;
+        }
+        update_save_char("server_app_version", version_str);
+        furi_string_free(manifest_data);
+    }
+    // Only check for an update if an hour or more has passed.
+    if (update_is_update_time(time_current))
+    {
+        char app_version[32];
+        if (!update_load_char("app_version", app_version, sizeof(app_version)))
+        {
+            FURI_LOG_E(TAG, "Failed to load app version");
+            return false;
+        }
+        // Check if the app version is different from the server version.
+        if (!update_is_str(app_version, version_str))
+        {
+            easy_flipper_dialog("Update available", "New update available!\nPress BACK to download.");
+            return true; // Update available.
+        }
+        FURI_LOG_I(TAG, "No update available");
+        return false; // No update available.
+    }
+    FURI_LOG_I(TAG, "Not enough time has passed since the last update check");
+    return false; // Not yet time to update.
+}
+
+static bool update_get_fap_file(FlipperHTTP *fhttp, bool flipper_server)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "FlipperHTTP is NULL.");
+        return false;
+    }
+    char url[256];
+    fhttp->save_received_data = false;
+    fhttp->is_bytes_request = true;
+#ifndef FW_ORIGIN_Momentum
+    snprintf(
+        fhttp->file_path,
+        sizeof(fhttp->file_path),
+        STORAGE_EXT_PATH_PREFIX "/apps/%s/%s.fap", APP_FOLDER, FAP_ID);
+#else
+    if (strlen(MOM_FOLDER) == 0)
+        snprintf(
+            fhttp->file_path,
+            sizeof(fhttp->file_path),
+            STORAGE_EXT_PATH_PREFIX "/apps/%s/%s.fap", APP_FOLDER, FAP_ID);
+    else
+        snprintf(
+            fhttp->file_path,
+            sizeof(fhttp->file_path),
+            STORAGE_EXT_PATH_PREFIX "/apps/%s/%s/%s.fap", APP_FOLDER, MOM_FOLDER, FAP_ID);
+#endif
+    if (flipper_server)
+    {
+        uint8_t target;
+        target = furi_hal_version_get_hw_target();
+        uint16_t api_major, api_minor;
+        furi_hal_info_get_api_version(&api_major, &api_minor);
+        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);
+    }
+    else
+    {
+        snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/app/download/%s/", FAP_ID);
+    }
+    return flipper_http_request(fhttp, BYTES, url, "{\"Content-Type\": \"application/octet-stream\"}", NULL);
+}
+
+// Updates the app. Uses the supplied current time for validating if update check should proceed.
+static bool update_update_app(FlipperHTTP *fhttp, DateTime *time_current, bool use_flipper_api)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "fhttp is NULL");
+        return false;
+    }
+    if (!update_last_app_update(fhttp, use_flipper_api))
+    {
+        FURI_LOG_E(TAG, "Failed to fetch last app update");
+        return false;
+    }
+    fhttp->state = RECEIVING;
+    furi_timer_start(fhttp->get_timeout_timer, TIMEOUT_DURATION_TICKS);
+    while (fhttp->state == RECEIVING && furi_timer_is_running(fhttp->get_timeout_timer) > 0)
+    {
+        furi_delay_ms(100);
+    }
+    furi_timer_stop(fhttp->get_timeout_timer);
+    if (update_parse_last_app_update(fhttp, time_current, use_flipper_api))
+    {
+        if (!update_get_fap_file(fhttp, false))
+        {
+            FURI_LOG_E(TAG, "Failed to fetch fap file 1");
+            return false;
+        }
+        fhttp->state = RECEIVING;
+
+        while (fhttp->state == RECEIVING)
+        {
+            furi_delay_ms(100);
+        }
+
+        if (fhttp->state == ISSUE)
+        {
+            FURI_LOG_E(TAG, "Failed to fetch fap file 2");
+            easy_flipper_dialog("Update Error", "Failed to download the\nupdate file.\nPlease try again.");
+            return false;
+        }
+        return true;
+    }
+
+    FURI_LOG_I(TAG, "No update available");
+    return false; // No update available.
+}
+
+// Handles the app update routine. This function obtains the current RTC time,
+// checks the "last_checked" value, and if it is more than one hour old, calls for an update.
+bool update_is_ready(FlipperHTTP *fhttp, bool use_flipper_api)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "fhttp is NULL");
+        return false;
+    }
+    DateTime rtc_time;
+    furi_hal_rtc_get_datetime(&rtc_time);
+    char last_checked[32];
+    if (!update_load_char("last_checked", last_checked, sizeof(last_checked)))
+    {
+        // First time – save the current time and check for an update.
+        if (!update_save_rtc_time(&rtc_time))
+        {
+            FURI_LOG_E(TAG, "Failed to save RTC time");
+            return false;
+        }
+        return update_update_app(fhttp, &rtc_time, use_flipper_api);
+    }
+    else
+    {
+        // Check if the current RTC time is at least one hour past the stored time.
+        if (update_is_update_time(&rtc_time))
+        {
+            if (!update_update_app(fhttp, &rtc_time, use_flipper_api))
+            {
+                // save the last_checked for the next check.
+                if (!update_save_rtc_time(&rtc_time))
+                {
+                    FURI_LOG_E(TAG, "Failed to save RTC time");
+                    return false;
+                }
+                return false;
+            }
+            // Save the current time for the next check.
+            if (!update_save_rtc_time(&rtc_time))
+            {
+                FURI_LOG_E(TAG, "Failed to save RTC time");
+                return false;
+            }
+            return true;
+        }
+        return false; // No update necessary.
+    }
+}

+ 8 - 0
flip_social/update/update.h

@@ -0,0 +1,8 @@
+#pragma once
+#include <flip_social.h>
+#define BUILD_ID "6714d6326cb04a64f7ec2328"
+#define APP_ID "flip_social"
+#define FAP_ID "flip_social"
+#define APP_FOLDER "GPIO"
+#define MOM_FOLDER "FlipperHTTP"
+bool update_is_ready(FlipperHTTP *fhttp, bool use_flipper_api);

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä