Explorar o código

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

Willy-JL hai 1 ano
pai
achega
25d2df0fb6
Modificáronse 31 ficheiros con 3865 adicións e 3559 borrados
  1. 14 12
      flip_social/README.md
  2. 339 751
      flip_social/alloc/flip_social_alloc.c
  3. 2 3
      flip_social/alloc/flip_social_alloc.h
  4. 38 4
      flip_social/app.c
  5. 1 1
      flip_social/application.fam
  6. 13 0
      flip_social/assets/CHANGELOG.md
  7. 14 12
      flip_social/assets/README.md
  8. 892 32
      flip_social/callback/flip_social_callback.c
  9. 85 37
      flip_social/callback/flip_social_callback.h
  10. 0 1032
      flip_social/draw/flip_social_draw.c
  11. 0 71
      flip_social/draw/flip_social_draw.h
  12. 198 139
      flip_social/easy_flipper/easy_flipper.c
  13. 61 61
      flip_social/easy_flipper/easy_flipper.h
  14. 104 86
      flip_social/explore/flip_social_explore.c
  15. 3 2
      flip_social/explore/flip_social_explore.h
  16. 214 136
      flip_social/feed/flip_social_feed.c
  17. 4 4
      flip_social/feed/flip_social_feed.h
  18. 204 167
      flip_social/flip_social.c
  19. 223 219
      flip_social/flip_social.h
  20. 195 113
      flip_social/flip_storage/flip_social_storage.c
  21. 21 17
      flip_social/flip_storage/flip_social_storage.h
  22. 291 165
      flip_social/flipper_http/flipper_http.c
  23. 98 60
      flip_social/flipper_http/flipper_http.h
  24. 77 76
      flip_social/friends/flip_social_friends.c
  25. 2 3
      flip_social/friends/flip_social_friends.h
  26. 217 136
      flip_social/jsmn/jsmn.c
  27. 49 48
      flip_social/jsmn/jsmn.h
  28. 191 169
      flip_social/messages/flip_social_messages.c
  29. 3 3
      flip_social/messages/flip_social_messages.h
  30. 162 0
      flip_social/text_input/rpc_keyboard.h
  31. 150 0
      flip_social/text_input/rpc_keyboard_stub.c

+ 14 - 12
flip_social/README.md

@@ -6,7 +6,7 @@ The highlight of this app is customizable pre-saves, which, as explained below,
 FlipSocial uses the FlipperHTTP flash for the WiFi Devboard, first introduced in the WebCrawler app: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
 
 ## Requirements
-- WiFi Developer Board or Raspberry Pi Pico W with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
+- WiFi Developer Board, Raspberry Pi, or ESP32 Device with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
 - WiFi Access Point
 
 
@@ -46,21 +46,22 @@ FlipSocial uses the FlipperHTTP flash for the WiFi Devboard, first introduced in
 - Direct Messaging
 
 **v0.5**
-- Improved memory allocation
-- Improved Feed Page
+- Improve memory allocation
+- Improve Feed Page
 - Raspberry Pi Pico W Support
 
 **v0.6**
-- Improved memory allocation
-- Fixed bugs in Direct Messaging View
-- Fixed bugs in Pre-Save View
+- Improve memory allocation
+- Update the Direct Messaging View
+- Update the Pre-Save View
 
 **v0.7**
-- Improved User Profile (Bio, friend count, block)
-- Improved Explore Page
+- Improve memory allocation
+- Loading screens.
 
 **v0.8**
-- Create and Post Pixel Art
+- Improve User Profile
+- Improve Explore Page
 
 **v1.0**
 - Official Release
@@ -88,8 +89,9 @@ This is a big project, and I welcome all contributors, especially developers int
 - **Solution 3:** Ensure your WiFi Devboard is plugged in, then restart your Flipper device.
 
 5. Out of memory when starting the app or after visiting the feed and post views back-to-back.
-- **Solution:** Restart your Flipper device.
+- **Solution 1:** Restart your Flipper device.
+- **Solution 2:** Update the app to version 0.7 (or higher).
 
-6. I can no longer access my Direct Messages.
+6. I can no longer access the Messages.
 - **Solution 1:** Uppdate the app to version 0.6.3 (or higher)
-- **Solution 2:** Click the logout button then login again.
+- **Solution 2:** Click the logout button then login again. Make sure your password is correct before clicking "Login".

+ 339 - 751
flip_social/alloc/flip_social_alloc.c

@@ -1,20 +1,34 @@
 #include <alloc/flip_social_alloc.h>
 
-FlipSocialApp* flip_social_app_alloc() {
+FlipSocialApp *flip_social_app_alloc()
+{
     // Initiailize the app
-    FlipSocialApp* app = (FlipSocialApp*)malloc(sizeof(FlipSocialApp));
+    FlipSocialApp *app = (FlipSocialApp *)malloc(sizeof(FlipSocialApp));
 
     // Initialize gui
-    Gui* gui = furi_record_open(RECORD_GUI);
+    Gui *gui = furi_record_open(RECORD_GUI);
 
     // Initialize UART
-    if(!flipper_http_init(flipper_http_rx_callback, app)) {
+    if (!flipper_http_init(flipper_http_rx_callback, app))
+    {
         FURI_LOG_E(TAG, "Failed to initialize UART");
         return NULL;
     }
 
     // Allocate ViewDispatcher
-    if(!easy_flipper_set_view_dispatcher(&app->view_dispatcher, gui, app)) {
+    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, "Error, try again.", flip_social_callback_to_submenu_logged_out, &app->view_dispatcher))
+    {
         return NULL;
     }
 
@@ -27,6 +41,7 @@ FlipSocialApp* flip_social_app_alloc() {
     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;
@@ -34,909 +49,482 @@ FlipSocialApp* flip_social_app_alloc() {
     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;
-    if(!easy_flipper_set_buffer(
-           &app->wifi_ssid_logged_out_temp_buffer, app->wifi_ssid_logged_out_temp_buffer_size)) {
+    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)) {
+    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)) {
+    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)) {
+    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_username_logged_out_temp_buffer,
-           app->register_username_logged_out_temp_buffer_size)) {
+    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_logged_out_temp_buffer,
-           app->register_password_logged_out_temp_buffer_size)) {
+    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->register_password_2_logged_out_temp_buffer,
-           app->register_password_2_logged_out_temp_buffer_size)) {
+    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_password_logged_in_temp_buffer,
-           app->change_password_logged_in_temp_buffer_size)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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->compose_pre_save_logged_in, app->compose_pre_save_logged_in_temp_buffer_size)) {
+    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->wifi_ssid_logged_in, app->wifi_ssid_logged_in_temp_buffer_size)) {
+    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_password_logged_in, app->wifi_password_logged_in_temp_buffer_size)) {
+    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->login_username_logged_in, app->login_username_logged_in_temp_buffer_size)) {
+    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->messages_new_message_logged_in,
-           app->messages_new_message_logged_in_temp_buffer_size)) {
+    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_temp_buffer,
-           app->messages_new_message_logged_in_temp_buffer_size)) {
+    //
+    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->message_user_choice_logged_in,
-           app->message_user_choice_logged_in_temp_buffer_size)) {
+    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_temp_buffer,
-           app->message_user_choice_logged_in_temp_buffer_size)) {
+    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(
-           &selected_message, app->message_user_choice_logged_in_temp_buffer_size)) {
+    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(
-           &last_explore_response, app->message_user_choice_logged_in_temp_buffer_size)) {
+    if (!easy_flipper_set_buffer(&selected_message, app->message_user_choice_logged_in_temp_buffer_size))
+    {
         return NULL;
     }
-
-    // Allocate Submenu(s)
-    if(!easy_flipper_set_submenu(
-           &app->submenu_logged_out,
-           FlipSocialViewLoggedOutSubmenu,
-           "FlipSocial v0.6",
-           flip_social_callback_exit_app,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_buffer(&app->explore_logged_in, app->explore_logged_in_temp_buffer_size))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_logged_in,
-           FlipSocialViewLoggedInSubmenu,
-           "FlipSocial v0.6",
-           flip_social_callback_exit_app,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_buffer(&app->explore_logged_in_temp_buffer, app->explore_logged_in_temp_buffer_size))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_compose,
-           FlipSocialViewLoggedInCompose,
-           "Create A Post",
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_buffer(&app->message_users_logged_in, app->message_users_logged_in_temp_buffer_size))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_explore,
-           FlipSocialViewLoggedInExploreSubmenu,
-           "Explore",
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_buffer(&app->message_users_logged_in_temp_buffer, app->message_users_logged_in_temp_buffer_size))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_friends,
-           FlipSocialViewLoggedInFriendsSubmenu,
-           "Friends",
-           flip_social_callback_to_profile_logged_in,
-           &app->view_dispatcher)) {
+
+    // Allocate Submenu(s)
+    if (!easy_flipper_set_submenu(&app->submenu_logged_out, FlipSocialViewLoggedOutSubmenu, "FlipSocial v0.8", flip_social_callback_exit_app, &app->view_dispatcher))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_messages,
-           FlipSocialViewLoggedInMessagesSubmenu,
-           "Messages",
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_submenu(&app->submenu_logged_in, FlipSocialViewLoggedInSubmenu, "FlipSocial v0.8", flip_social_callback_exit_app, &app->view_dispatcher))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_submenu(
-           &app->submenu_messages_user_choices,
-           FlipSocialViewLoggedInMessagesUserChoices,
-           "Users",
-           flip_social_callback_to_messages_logged_in,
-           &app->view_dispatcher)) {
+
+    if (!easy_flipper_set_submenu(&app->submenu_messages_user_choices, FlipSocialViewLoggedInMessagesUserChoices, "Users", flip_social_callback_to_messages_logged_in, &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);
-    //
-    submenu_add_item(
-        app->submenu_compose,
-        "Add Pre-Save",
-        FlipSocialSubmenuComposeIndexAddPreSave,
-        flip_social_callback_submenu_choices,
-        app);
+    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);
 
-    // Allocate View(s)
-    if(!easy_flipper_set_view(
-           &app->view_process_login,
-           FlipSocialViewLoggedOutProcessLogin,
-           flip_social_callback_draw_login,
-           NULL,
-           flip_social_callback_to_login_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_register,
-           FlipSocialViewLoggedOutProcessRegister,
-           flip_social_callback_draw_register,
-           NULL,
-           flip_social_callback_to_register_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_feed,
-           FlipSocialViewLoggedInFeed,
-           flip_social_callback_draw_feed,
-           NULL,
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_compose,
-           FlipSocialViewLoggedInProcessCompose,
-           flip_social_callback_draw_compose,
-           NULL,
-           flip_social_callback_to_compose_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_explore,
-           FlipSocialViewLoggedInExploreProccess,
-           flip_social_callback_draw_explore,
-           NULL,
-           flip_social_callback_to_explore_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_friends,
-           FlipSocialViewLoggedInFriendsProcess,
-           flip_social_callback_draw_friends,
-           NULL,
-           flip_social_callback_to_friends_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_view(
-           &app->view_process_messages,
-           FlipSocialViewLoggedInMessagesProcess,
-           flip_social_callback_draw_messages,
-           NULL,
-           flip_social_callback_to_messages_logged_in,
-           &app->view_dispatcher,
-           app)) {
+    // Setup Variable Item List(s)
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_out_wifi_settings, FlipSocialViewLoggedOutWifiSettings, flip_social_text_input_logged_out_wifi_settings_item_selected, flip_social_callback_to_submenu_logged_out, &app->view_dispatcher, app))
+    {
         return NULL;
     }
-
-    // Setup Variable Item List(s)
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_out_wifi_settings,
-           FlipSocialViewLoggedOutWifiSettings,
-           flip_social_text_input_logged_out_wifi_settings_item_selected,
-           flip_social_callback_to_submenu_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_out_login,
-           FlipSocialViewLoggedOutLogin,
-           flip_social_text_input_logged_out_login_item_selected,
-           flip_social_callback_to_submenu_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_out_register,
-           FlipSocialViewLoggedOutRegister,
-           flip_social_text_input_logged_out_register_item_selected,
-           flip_social_callback_to_submenu_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_in_profile,
-           FlipSocialViewLoggedInProfile,
-           flip_social_text_input_logged_in_profile_item_selected,
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_in_settings,
-           FlipSocialViewLoggedInSettings,
-           flip_social_text_input_logged_in_settings_item_selected,
-           flip_social_callback_to_submenu_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_variable_item_list(
-           &app->variable_item_list_logged_in_settings_wifi,
-           FlipSocialViewLoggedInSettingsWifi,
-           flip_social_text_input_logged_in_wifi_settings_item_selected,
-           flip_social_callback_to_settings_logged_in,
-           &app->view_dispatcher,
-           app)) {
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_out_login, FlipSocialViewLoggedOutLogin, flip_social_text_input_logged_out_login_item_selected, flip_social_callback_to_submenu_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_out_register, FlipSocialViewLoggedOutRegister, flip_social_text_input_logged_out_register_item_selected, flip_social_callback_to_submenu_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_in_profile, FlipSocialViewLoggedInProfile, flip_social_text_input_logged_in_profile_item_selected, flip_social_callback_to_submenu_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_in_settings, FlipSocialViewLoggedInSettings, flip_social_text_input_logged_in_settings_item_selected, flip_social_callback_to_submenu_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_variable_item_list(&app->variable_item_list_logged_in_settings_wifi, FlipSocialViewLoggedInSettingsWifi, flip_social_text_input_logged_in_wifi_settings_item_selected, flip_social_callback_to_settings_logged_in, &app->view_dispatcher, app))
+    {
         return NULL;
     }
 
-    app->variable_item_logged_out_wifi_settings_ssid = variable_item_list_add(
-        app->variable_item_list_logged_out_wifi_settings, "SSID", 1, NULL, NULL);
-    app->variable_item_logged_out_wifi_settings_password = variable_item_list_add(
-        app->variable_item_list_logged_out_wifi_settings, "Password", 1, NULL, NULL);
+    app->variable_item_logged_out_wifi_settings_ssid = variable_item_list_add(app->variable_item_list_logged_out_wifi_settings, "SSID", 1, NULL, app);
+    app->variable_item_logged_out_wifi_settings_password = variable_item_list_add(app->variable_item_list_logged_out_wifi_settings, "Password", 1, NULL, app);
     //
-    app->variable_item_logged_out_login_username = variable_item_list_add(
-        app->variable_item_list_logged_out_login, "Username", 1, NULL, NULL);
-    app->variable_item_logged_out_login_password = variable_item_list_add(
-        app->variable_item_list_logged_out_login, "Password", 1, NULL, NULL);
-    app->variable_item_logged_out_login_button =
-        variable_item_list_add(app->variable_item_list_logged_out_login, "Login", 0, NULL, NULL);
+    app->variable_item_logged_out_login_username = variable_item_list_add(app->variable_item_list_logged_out_login, "Username", 1, NULL, app);
+    app->variable_item_logged_out_login_password = variable_item_list_add(app->variable_item_list_logged_out_login, "Password", 1, NULL, app);
+    app->variable_item_logged_out_login_button = variable_item_list_add(app->variable_item_list_logged_out_login, "Login", 0, NULL, app);
     //
-    app->variable_item_logged_out_register_username = variable_item_list_add(
-        app->variable_item_list_logged_out_register, "Username", 1, NULL, NULL);
-    app->variable_item_logged_out_register_password = variable_item_list_add(
-        app->variable_item_list_logged_out_register, "Password", 1, NULL, NULL);
-    app->variable_item_logged_out_register_password_2 = variable_item_list_add(
-        app->variable_item_list_logged_out_register, "Confirm Password", 1, NULL, NULL);
-    app->variable_item_logged_out_register_button = variable_item_list_add(
-        app->variable_item_list_logged_out_register, "Register", 0, NULL, NULL);
+    app->variable_item_logged_out_register_username = variable_item_list_add(app->variable_item_list_logged_out_register, "Username", 1, NULL, app);
+    app->variable_item_logged_out_register_password = variable_item_list_add(app->variable_item_list_logged_out_register, "Password", 1, NULL, app);
+    app->variable_item_logged_out_register_password_2 = variable_item_list_add(app->variable_item_list_logged_out_register, "Confirm Password", 1, NULL, app);
+    app->variable_item_logged_out_register_button = variable_item_list_add(app->variable_item_list_logged_out_register, "Register", 0, NULL, app);
     //
-    app->variable_item_logged_in_profile_username = variable_item_list_add(
-        app->variable_item_list_logged_in_profile, "Username", 0, NULL, NULL);
-    app->variable_item_logged_in_profile_change_password = variable_item_list_add(
-        app->variable_item_list_logged_in_profile, "Change Password", 0, NULL, NULL);
-    app->variable_item_logged_in_profile_friends = variable_item_list_add(
-        app->variable_item_list_logged_in_profile, "Friends", 0, NULL, NULL);
+    app->variable_item_logged_in_profile_username = variable_item_list_add(app->variable_item_list_logged_in_profile, "Username", 1, NULL, app);
+    app->variable_item_logged_in_profile_change_password = variable_item_list_add(app->variable_item_list_logged_in_profile, "Password", 1, NULL, app);
+    app->variable_item_logged_in_profile_change_bio = variable_item_list_add(app->variable_item_list_logged_in_profile, "Bio", 1, NULL, app);
+    app->variable_item_logged_in_profile_friends = variable_item_list_add(app->variable_item_list_logged_in_profile, "Friends", 0, NULL, app);
     //
-    app->variable_item_logged_in_settings_about =
-        variable_item_list_add(app->variable_item_list_logged_in_settings, "About", 0, NULL, NULL);
-    app->variable_item_logged_in_settings_wifi =
-        variable_item_list_add(app->variable_item_list_logged_in_settings, "WiFi", 0, NULL, NULL);
+    app->variable_item_logged_in_settings_about = variable_item_list_add(app->variable_item_list_logged_in_settings, "About", 0, NULL, app);
+    app->variable_item_logged_in_settings_wifi = variable_item_list_add(app->variable_item_list_logged_in_settings, "WiFi", 0, NULL, app);
     //
-    app->variable_item_logged_in_wifi_settings_ssid = variable_item_list_add(
-        app->variable_item_list_logged_in_settings_wifi, "SSID", 1, NULL, NULL);
-    app->variable_item_logged_in_wifi_settings_password = variable_item_list_add(
-        app->variable_item_list_logged_in_settings_wifi, "Password", 1, NULL, NULL);
+    app->variable_item_logged_in_wifi_settings_ssid = variable_item_list_add(app->variable_item_list_logged_in_settings_wifi, "SSID", 1, NULL, app);
+    app->variable_item_logged_in_wifi_settings_password = variable_item_list_add(app->variable_item_list_logged_in_settings_wifi, "Password", 1, NULL, app);
 
     // Setup Text Input(s)
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_wifi_settings_ssid,
-           FlipSocialViewLoggedOutWifiSettingsSSIDInput,
-           "Enter SSID",
-           app->wifi_ssid_logged_out_temp_buffer,
-           app->wifi_ssid_logged_out_temp_buffer_size,
-           flip_social_logged_out_wifi_settings_ssid_updated,
-           flip_social_callback_to_wifi_settings_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_wifi_settings_password,
-           FlipSocialViewLoggedOutWifiSettingsPasswordInput,
-           "Enter Password",
-           app->wifi_password_logged_out_temp_buffer,
-           app->wifi_password_logged_out_temp_buffer_size,
-           flip_social_logged_out_wifi_settings_password_updated,
-           flip_social_callback_to_wifi_settings_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_login_username,
-           FlipSocialViewLoggedOutLoginUsernameInput,
-           "Enter Username",
-           app->login_username_logged_out_temp_buffer,
-           app->login_username_logged_out_temp_buffer_size,
-           flip_social_logged_out_login_username_updated,
-           flip_social_callback_to_login_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_login_password,
-           FlipSocialViewLoggedOutLoginPasswordInput,
-           "Enter Password",
-           app->login_password_logged_out_temp_buffer,
-           app->login_password_logged_out_temp_buffer_size,
-           flip_social_logged_out_login_password_updated,
-           flip_social_callback_to_login_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_register_username,
-           FlipSocialViewLoggedOutRegisterUsernameInput,
-           "Enter Username",
-           app->register_username_logged_out_temp_buffer,
-           app->register_username_logged_out_temp_buffer_size,
-           flip_social_logged_out_register_username_updated,
-           flip_social_callback_to_register_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_register_password,
-           FlipSocialViewLoggedOutRegisterPasswordInput,
-           "Enter Password",
-           app->register_password_logged_out_temp_buffer,
-           app->register_password_logged_out_temp_buffer_size,
-           flip_social_logged_out_register_password_updated,
-           flip_social_callback_to_register_logged_out,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_out_register_password_2,
-           FlipSocialViewLoggedOutRegisterPassword2Input,
-           "Confirm Password",
-           app->register_password_2_logged_out_temp_buffer,
-           app->register_password_2_logged_out_temp_buffer_size,
-           flip_social_logged_out_register_password_2_updated,
-           flip_social_callback_to_register_logged_out,
-           &app->view_dispatcher,
-           app)) {
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_wifi_settings_ssid, FlipSocialViewLoggedOutWifiSettingsSSIDInput, "Enter SSID", app->wifi_ssid_logged_out_temp_buffer, app->wifi_ssid_logged_out_temp_buffer_size, flip_social_logged_out_wifi_settings_ssid_updated, flip_social_callback_to_wifi_settings_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_wifi_settings_password, FlipSocialViewLoggedOutWifiSettingsPasswordInput, "Enter Password", app->wifi_password_logged_out_temp_buffer, app->wifi_password_logged_out_temp_buffer_size, flip_social_logged_out_wifi_settings_password_updated, flip_social_callback_to_wifi_settings_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_login_username, FlipSocialViewLoggedOutLoginUsernameInput, "Enter Username", app->login_username_logged_out_temp_buffer, app->login_username_logged_out_temp_buffer_size, flip_social_logged_out_login_username_updated, flip_social_callback_to_login_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_login_password, FlipSocialViewLoggedOutLoginPasswordInput, "Enter Password", app->login_password_logged_out_temp_buffer, app->login_password_logged_out_temp_buffer_size, flip_social_logged_out_login_password_updated, flip_social_callback_to_login_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_register_username, FlipSocialViewLoggedOutRegisterUsernameInput, "Enter Username", app->register_username_logged_out_temp_buffer, app->register_username_logged_out_temp_buffer_size, flip_social_logged_out_register_username_updated, flip_social_callback_to_register_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_register_password, FlipSocialViewLoggedOutRegisterPasswordInput, "Enter Password", app->register_password_logged_out_temp_buffer, app->register_password_logged_out_temp_buffer_size, flip_social_logged_out_register_password_updated, flip_social_callback_to_register_logged_out, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_out_register_password_2, FlipSocialViewLoggedOutRegisterPassword2Input, "Confirm Password", app->register_password_2_logged_out_temp_buffer, app->register_password_2_logged_out_temp_buffer_size, flip_social_logged_out_register_password_2_updated, flip_social_callback_to_register_logged_out, &app->view_dispatcher, app))
+    {
         return NULL;
     }
     //
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_change_password,
-           FlipSocialViewLoggedInChangePasswordInput,
-           "Enter New Password",
-           app->change_password_logged_in_temp_buffer,
-           app->change_password_logged_in_temp_buffer_size,
-           flip_social_logged_in_profile_change_password_updated,
-           flip_social_callback_to_profile_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_compose_pre_save_input,
-           FlipSocialViewLoggedInComposeAddPreSaveInput,
-           "Enter Pre-Save Message",
-           app->compose_pre_save_logged_in_temp_buffer,
-           app->compose_pre_save_logged_in_temp_buffer_size,
-           flip_social_logged_in_compose_pre_save_updated,
-           flip_social_callback_to_compose_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_wifi_settings_ssid,
-           FlipSocialViewLoggedInWifiSettingsSSIDInput,
-           "Enter SSID",
-           app->wifi_ssid_logged_in_temp_buffer,
-           app->wifi_ssid_logged_in_temp_buffer_size,
-           flip_social_logged_in_wifi_settings_ssid_updated,
-           flip_social_callback_to_wifi_settings_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_wifi_settings_password,
-           FlipSocialViewLoggedInWifiSettingsPasswordInput,
-           "Enter Password",
-           app->wifi_password_logged_in_temp_buffer,
-           app->wifi_password_logged_in_temp_buffer_size,
-           flip_social_logged_in_wifi_settings_password_updated,
-           flip_social_callback_to_wifi_settings_logged_in,
-           &app->view_dispatcher,
-           app)) {
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_change_password, FlipSocialViewLoggedInChangePasswordInput, "Password", app->change_password_logged_in_temp_buffer, app->change_password_logged_in_temp_buffer_size, flip_social_logged_in_profile_change_password_updated, flip_social_callback_to_profile_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_change_bio, FlipSocialViewLoggedInChangeBioInput, "Bio", app->change_bio_logged_in_temp_buffer, app->change_bio_logged_in_temp_buffer_size, flip_social_logged_in_profile_change_bio_updated, flip_social_callback_to_profile_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_compose_pre_save_input, FlipSocialViewLoggedInComposeAddPreSaveInput, "Enter Pre-Save Message", app->compose_pre_save_logged_in_temp_buffer, app->compose_pre_save_logged_in_temp_buffer_size, flip_social_logged_in_compose_pre_save_updated, flip_social_callback_to_compose_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_wifi_settings_ssid, FlipSocialViewLoggedInWifiSettingsSSIDInput, "Enter SSID", app->wifi_ssid_logged_in_temp_buffer, app->wifi_ssid_logged_in_temp_buffer_size, flip_social_logged_in_wifi_settings_ssid_updated, flip_social_callback_to_wifi_settings_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
+    }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_wifi_settings_password, FlipSocialViewLoggedInWifiSettingsPasswordInput, "Enter Password", app->wifi_password_logged_in_temp_buffer, app->wifi_password_logged_in_temp_buffer_size, flip_social_logged_in_wifi_settings_password_updated, flip_social_callback_to_wifi_settings_logged_in, &app->view_dispatcher, app))
+    {
         return NULL;
     }
     //
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_messages_new_message,
-           FlipSocialViewLoggedInMessagesNewMessageInput,
-           "Enter Message",
-           app->messages_new_message_logged_in_temp_buffer,
-           app->messages_new_message_logged_in_temp_buffer_size,
-           flip_social_logged_in_messages_new_message_updated,
-           flip_social_callback_to_messages_logged_in,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
-    if(!easy_flipper_set_uart_text_input(
-           &app->text_input_logged_in_messages_new_message_user_choices,
-           FlipSocialViewLoggedInMessagesNewMessageUserChoicesInput,
-           "Enter Message",
-           app->message_user_choice_logged_in_temp_buffer,
-           app->message_user_choice_logged_in_temp_buffer_size,
-           flip_social_logged_in_messages_user_choice_message_updated,
-           flip_social_callback_to_messages_user_choices,
-           &app->view_dispatcher,
-           app)) {
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_messages_new_message, FlipSocialViewLoggedInMessagesNewMessageInput, "Enter Message", app->messages_new_message_logged_in_temp_buffer, app->messages_new_message_logged_in_temp_buffer_size, flip_social_logged_in_messages_new_message_updated, flip_social_callback_to_messages_logged_in, &app->view_dispatcher, app))
+    {
         return NULL;
     }
-
-    // Setup About(s)
-    if(!easy_flipper_set_widget(
-           &app->widget_logged_out_about,
-           FlipSocialViewLoggedOutAbout,
-           "Welcome to FlipSocial\n---\nThe social media app for\nFlipper Zero, created by\nJBlanked: www.flipsocial.net\n---\nPress BACK to return.",
-           flip_social_callback_to_submenu_logged_out,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_messages_new_message_user_choices, FlipSocialViewLoggedInMessagesNewMessageUserChoicesInput, "Enter Message", app->message_user_choice_logged_in_temp_buffer, app->message_user_choice_logged_in_temp_buffer_size, flip_social_logged_in_messages_user_choice_message_updated, flip_social_callback_to_messages_user_choices, &app->view_dispatcher, app))
+    {
         return NULL;
     }
-    if(!easy_flipper_set_widget(
-           &app->widget_logged_in_about,
-           FlipSocialViewLoggedInSettingsAbout,
-           "Welcome to FlipSocial\n---\nThe social media app for\nFlipper Zero, created by\nJBlanked: www.flipsocial.net\n---\nPress BACK to return.",
-           flip_social_callback_to_settings_logged_in,
-           &app->view_dispatcher)) {
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_explore, FlipSocialViewLoggedInExploreInput, "Enter Username or Keyword", app->explore_logged_in_temp_buffer, app->explore_logged_in_temp_buffer_size, flip_social_logged_in_explore_updated, flip_social_callback_to_submenu_logged_in, &app->view_dispatcher, app))
+    {
         return NULL;
     }
-
-    // load the playlist
-    if(load_playlist(&app->pre_saved_messages)) {
-        // Update the playlist submenu
-        for(uint32_t i = 0; i < app->pre_saved_messages.count; i++) {
-            submenu_add_item(
-                app->submenu_compose,
-                app->pre_saved_messages.messages[i],
-                FlipSocialSubemnuComposeIndexStartIndex + i,
-                flip_social_callback_submenu_choices,
-                app);
-        }
+    if (!easy_flipper_set_uart_text_input(&app->text_input_logged_in_message_users, FlipSocialViewLoggedInMessageUsersInput, "Enter Username or Keyword", app->message_users_logged_in_temp_buffer, app->message_users_logged_in_temp_buffer_size, flip_social_logged_in_message_users_updated, flip_social_callback_to_submenu_logged_in, &app->view_dispatcher, app))
+    {
+        return NULL;
     }
 
     // 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->is_logged_in,
-           app->is_logged_in_size))
+    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);
+        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 {
+    }
+    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_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->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_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->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_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_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->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_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->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_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->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 (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';
+        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 (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 (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 (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);
+        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';
+            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 (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);
+        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';
+            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);
+        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';
+            app->wifi_ssid_logged_out_temp_buffer[app->wifi_ssid_logged_in_temp_buffer_size - 1] = '\0';
         }
 
         auth_headers_alloc();
 
         // set variable item text (ommit the passwords)
-        variable_item_set_current_value_text(
-            app->variable_item_logged_in_wifi_settings_ssid, app->wifi_ssid_logged_in);
-        variable_item_set_current_value_text(
-            app->variable_item_logged_out_wifi_settings_ssid, app->wifi_ssid_logged_out);
-        variable_item_set_current_value_text(
-            app->variable_item_logged_out_login_username, app->login_username_logged_out);
-        variable_item_set_current_value_text(
-            app->variable_item_logged_in_profile_username, app->login_username_logged_in);
+        variable_item_set_current_value_text(app->variable_item_logged_in_wifi_settings_ssid, app->wifi_ssid_logged_in);
+        variable_item_set_current_value_text(app->variable_item_logged_out_wifi_settings_ssid, app->wifi_ssid_logged_out);
+        variable_item_set_current_value_text(app->variable_item_logged_out_login_username, app->login_username_logged_out);
+        variable_item_set_current_value_text(app->variable_item_logged_in_profile_username, app->login_username_logged_in);
+        variable_item_set_current_value_text(app->variable_item_logged_in_profile_change_bio, app->change_bio_logged_in);
         //
 
-        if(app->is_logged_in != NULL && strcmp(app->is_logged_in, "true") == 0) {
+        if (app->is_logged_in != NULL && strcmp(app->is_logged_in, "true") == 0)
+        {
             view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-        } else {
+        }
+        else
+        {
             view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
         }
     }
 
     return app;
-}
+}

+ 2 - 3
flip_social/alloc/flip_social_alloc.h

@@ -3,12 +3,11 @@
 #include <flip_social.h>
 #include <callback/flip_social_callback.h>
 #include <flip_storage/flip_social_storage.h>
-#include <draw/flip_social_draw.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
+FlipSocialApp *flip_social_app_alloc();
+#endif

+ 38 - 4
flip_social/app.c

@@ -1,5 +1,5 @@
 // app.c
-#include <flip_social.h> // Include the FlipSocialApp structure
+#include <flip_social.h>             // Include the FlipSocialApp structure
 #include <alloc/flip_social_alloc.h> // Include the allocation functions
 
 /**
@@ -8,21 +8,55 @@
  * @param p Input parameter - unused
  * @return 0 to indicate success, -1 on failure
  */
-int32_t main_flip_social(void* p) {
+int32_t main_flip_social(void *p)
+{
     UNUSED(p);
 
     // Initialize the Hello World application
     app_instance = flip_social_app_alloc();
-    if(!app_instance) {
+    if (!app_instance)
+    {
         // Allocation failed
         return -1; // Indicate failure
     }
 
-    if(!flipper_http_ping()) {
+    if (!flipper_http_ping())
+    {
         FURI_LOG_E(TAG, "Failed to ping the device");
         return -1;
     }
 
+    // Thanks to Derek Jamison for the following edits
+    if (app_instance->wifi_ssid_logged_out != NULL &&
+        app_instance->wifi_password_logged_out != NULL)
+    {
+        // Try to wait for pong response.
+        uint8_t counter = 10;
+        while (fhttp.state == INACTIVE && --counter > 0)
+        {
+            FURI_LOG_D(TAG, "Waiting for PONG");
+            furi_delay_ms(100);
+        }
+
+        if (counter == 0)
+        {
+            DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS);
+            DialogMessage *message = dialog_message_alloc();
+            dialog_message_set_header(
+                message, "[FlipperHTTP Error]", 64, 0, AlignCenter, AlignTop);
+            dialog_message_set_text(
+                message,
+                "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.",
+                0,
+                63,
+                AlignLeft,
+                AlignBottom);
+            dialog_message_show(dialogs, message);
+            dialog_message_free(message);
+            furi_record_close(RECORD_DIALOGS);
+        }
+    }
+
     // Run the view dispatcher
     view_dispatcher_run(app_instance->view_dispatcher);
 

+ 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="0.6.3",
+    fap_version="0.8",
     fap_description="Social media platform for the Flipper Zero.",
 )

+ 13 - 0
flip_social/assets/CHANGELOG.md

@@ -1,3 +1,16 @@
+## 0.8 - New Features
+- Added support for RPC_KEYBOARD (thanks to Derek Jamison).
+- Introduced a bio feature in the Profile section: View and update your bio.
+- Enhanced the Explore view: Clicking on a user now displays their bio and friend count. You can also search for users.
+- Improved the Messages view: Users can now search for a contact to send messages.
+
+## 0.7
+- Improved memory allocation
+- Increased the max explore users from 50 to 100
+- Increased the max feed posts from 40 to 50.
+- Added loading screens.
+- Added updates from Derek Jamison
+
 ## 0.6
 - Improved memory allocation
 - Fixed bugs in Direct Messaging View

+ 14 - 12
flip_social/assets/README.md

@@ -6,7 +6,7 @@ The highlight of this app is customizable pre-saves, which, as explained below,
 FlipSocial uses the FlipperHTTP flash for the WiFi Devboard, first introduced in the WebCrawler app: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
 
 ## Requirements
-- WiFi Developer Board or Raspberry Pi Pico W with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
+- WiFi Developer Board, Raspberry Pi, or ESP32 Device with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
 - WiFi Access Point
 
 
@@ -46,21 +46,22 @@ FlipSocial uses the FlipperHTTP flash for the WiFi Devboard, first introduced in
 - Direct Messaging
 
 **v0.5**
-- Improved memory allocation
-- Improved Feed Page
+- Improve memory allocation
+- Improve Feed Page
 - Raspberry Pi Pico W Support
 
 **v0.6**
-- Improved memory allocation
-- Fixed bugs in Direct Messaging View
-- Fixed bugs in Pre-Save View
+- Improve memory allocation
+- Update the Direct Messaging View
+- Update the Pre-Save View
 
 **v0.7**
-- Improved User Profile (Bio, friend count, block)
-- Improved Explore Page
+- Improve memory allocation
+- Loading screens.
 
 **v0.8**
-- Create and Post Pixel Art
+- Improve User Profile
+- Improve Explore Page
 
 **v1.0**
 - Official Release
@@ -88,8 +89,9 @@ This is a big project, and I welcome all contributors, especially developers int
 - **Solution 3:** Ensure your WiFi Devboard is plugged in, then restart your Flipper device.
 
 5. Out of memory when starting the app or after visiting the feed and post views back-to-back.
-- **Solution:** Restart your Flipper device.
+- **Solution 1:** Restart your Flipper device.
+- **Solution 2:** Update the app to version 0.7 (or higher).
 
-6. I can no longer access my Direct Messages.
+6. I can no longer access the Messages.
 - **Solution 1:** Uppdate the app to version 0.6.3 (or higher)
-- **Solution 2:** Click the logout button then login again.
+- **Solution 2:** Click the logout button then login again. Make sure your password is correct before clicking "Login".

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 892 - 32
flip_social/callback/flip_social_callback.c


+ 85 - 37
flip_social/callback/flip_social_callback.h

@@ -6,7 +6,6 @@
 #include <friends/flip_social_friends.h>
 #include <explore/flip_social_explore.h>
 #include <feed/flip_social_feed.h>
-#include <draw/flip_social_draw.h>
 #include <flip_storage/flip_social_storage.h>
 
 /**
@@ -14,98 +13,98 @@
  * @param context The context - unused
  * @return next view id (FlipSocialViewLoggedOutSubmenu)
  */
-uint32_t flip_social_callback_to_submenu_logged_out(void* context);
+uint32_t flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_callback_exit_app(void *context);
 
 /**
  * @brief Handle ALL submenu item selections.
@@ -113,21 +112,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 flip_social_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 flip_social_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 flip_social_logged_out_wifi_settings_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the wifi settings (logged out) screen.
@@ -135,21 +134,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 flip_social_text_input_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 flip_social_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 flip_social_logged_out_login_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the login (logged out) screen.
@@ -157,42 +156,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 flip_social_text_input_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 flip_social_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 flip_social_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 flip_social_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 flip_social_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 flip_social_logged_in_wifi_settings_password_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the wifi settings (logged in) screen.
@@ -200,21 +199,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 flip_social_text_input_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 flip_social_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 flip_social_logged_in_profile_change_password_updated(void *context);
 
 /**
  * @brief Callback when a user selects a menu item in the profile (logged in) screen.
@@ -222,7 +221,8 @@ void flip_social_logged_in_profile_change_password_updated(void* context);
  * @param index The index of the selected item.
  * @return void
  */
-void flip_social_text_input_logged_in_profile_item_selected(void* context, uint32_t index);
+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.
@@ -230,20 +230,20 @@ void flip_social_text_input_logged_in_profile_item_selected(void* context, uint3
  * @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 flip_social_text_input_logged_in_settings_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 flip_social_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 flip_social_logged_in_messages_new_message_updated(void *context);
 
 /**
  * @brief Callback when the user selects a menu item in the register (logged out) screen.
@@ -251,6 +251,54 @@ 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);
-
-#endif
+void flip_social_text_input_logged_out_register_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);
+
+bool messages_dialog_alloc(bool free_first);
+bool feed_dialog_alloc();
+#endif

+ 0 - 1032
flip_social/draw/flip_social_draw.c

@@ -1,1032 +0,0 @@
-#include "flip_social_draw.h"
-Action action = ActionNone;
-bool flip_social_board_is_active(Canvas* canvas) {
-    if(fhttp.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 false;
-    }
-    return true;
-}
-
-void flip_social_handle_error(Canvas* canvas) {
-    if(fhttp.last_response != NULL) {
-        if(strstr(fhttp.last_response, "[ERROR] Not connected to Wifi. Failed to reconnect.") !=
-           NULL) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
-            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-        } else if(strstr(fhttp.last_response, "[ERROR] Failed to connect to Wifi.") != NULL) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
-            canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-        } else {
-            canvas_draw_str(canvas, 0, 42, "Failed...");
-            canvas_draw_str(canvas, 0, 52, "Update your credentials.");
-            canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-        }
-    } else {
-        canvas_draw_str(canvas, 0, 42, "Failed...");
-        canvas_draw_str(canvas, 0, 52, "Update your credentials.");
-        canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-    }
-}
-
-void on_input(const void* event, void* ctx) {
-    UNUSED(ctx);
-
-    InputKey key = ((InputEvent*)event)->key;
-    InputType type = ((InputEvent*)event)->type;
-
-    if(type != InputTypeRelease) {
-        return;
-    }
-
-    switch(key) {
-    case InputKeyOk:
-        action = ActionFlip;
-        break;
-    case InputKeyBack:
-        action = ActionBack;
-        break;
-    case InputKeyRight:
-        action = ActionNext;
-        break;
-    case InputKeyLeft:
-        action = ActionPrev;
-        break;
-    case InputKeyUp:
-        action = ActionPrev;
-        break;
-    case InputKeyDown:
-        action = ActionNext;
-        break;
-    default:
-        action = ActionNone;
-        break;
-    }
-}
-
-// Function to draw the message on the canvas with word wrapping
-void draw_user_message(Canvas* canvas, const char* user_message, int x, int y) {
-    if(user_message == NULL) {
-        FURI_LOG_E(TAG, "User message is NULL.");
-        return;
-    }
-
-    size_t msg_length = strlen(user_message);
-    size_t start = 0;
-    int line_num = 0;
-    char line[MAX_LINE_LENGTH + 1]; // Buffer for the current line (+1 for null terminator)
-
-    while(start < msg_length && line_num < 4) {
-        size_t remaining = msg_length - start;
-        size_t len = (remaining > MAX_LINE_LENGTH) ? MAX_LINE_LENGTH : remaining;
-
-        if(remaining > MAX_LINE_LENGTH) {
-            // Find the last space within the first 'len' characters
-            size_t last_space = len;
-            while(last_space > 0 && user_message[start + last_space - 1] != ' ') {
-                last_space--;
-            }
-
-            if(last_space > 0) {
-                len = last_space; // Adjust len to the position of the last space
-            }
-        }
-
-        // Copy the substring to 'line' and null-terminate it
-        memcpy(line, user_message + start, len);
-        line[len] = '\0'; // Ensure the string is null-terminated
-
-        // Draw the string on the canvas
-        // Adjust the y-coordinate based on the line number
-        canvas_draw_str_aligned(canvas, x, y + line_num * 10, AlignLeft, AlignTop, line);
-
-        // Update the start position for the next line
-        start += len;
-
-        // Skip any spaces to avoid leading spaces on the next line
-        while(start < msg_length && user_message[start] == ' ') {
-            start++;
-        }
-
-        // Increment the line number
-        line_num++;
-    }
-}
-
-void flip_social_callback_draw_compose(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-    if(!app_instance) {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
-    }
-    if(!selected_message) {
-        FURI_LOG_E(TAG, "Selected message is NULL");
-        return;
-    }
-
-    if(strlen(selected_message) > MAX_MESSAGE_LENGTH) {
-        FURI_LOG_E(TAG, "Message is too long");
-        return;
-    }
-
-    if(!flip_social_dialog_shown) {
-        flip_social_dialog_shown = true;
-        app_instance->input_event_queue = furi_record_open(RECORD_INPUT_EVENTS);
-        app_instance->input_event =
-            furi_pubsub_subscribe(app_instance->input_event_queue, on_input, NULL);
-        auth_headers_alloc();
-    }
-
-    draw_user_message(canvas, selected_message, 0, 2);
-
-    canvas_draw_icon(canvas, 0, 53, &I_ButtonLeft_4x7);
-    canvas_draw_str_aligned(canvas, 7, 54, AlignLeft, AlignTop, "Delete");
-    canvas_draw_icon(canvas, 52, 53, &I_ButtonBACK_10x8);
-    canvas_draw_str_aligned(canvas, 64, 54, AlignLeft, AlignTop, "Back");
-    canvas_draw_icon(canvas, 100, 53, &I_ButtonRight_4x7);
-    canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Post");
-
-    // handle action
-    switch(action) {
-    case ActionNone:
-        break;
-    case ActionBack:
-        flip_social_dialog_stop = true;
-        break;
-    case ActionNext:
-        // send selected_message
-        if(selected_message && app_instance->login_username_logged_in) {
-            if(strlen(selected_message) > MAX_MESSAGE_LENGTH) {
-                FURI_LOG_E(TAG, "Message is too long");
-                return;
-            }
-            // Send the selected_message
-            char command[256];
-            snprintf(
-                command,
-                sizeof(command),
-                "{\"username\":\"%s\",\"content\":\"%s\"}",
-                app_instance->login_username_logged_in,
-                selected_message);
-
-            if(!flipper_http_post_request_with_headers(
-                   "https://www.flipsocial.net/api/feed/post/", auth_headers, command)) {
-                FURI_LOG_E(TAG, "Failed to send HTTP request for feed");
-                fhttp.state = ISSUE;
-                return;
-            }
-
-            fhttp.state = RECEIVING;
-            furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        } else {
-            FURI_LOG_E(TAG, "Message or username is NULL");
-            return;
-        }
-        while(fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0) {
-            // Wait for the feed to be received
-            furi_delay_ms(100);
-
-            // Draw the resulting string on the canvas
-            canvas_draw_str(canvas, 0, 30, "Receiving..");
-        }
-        flip_social_dialog_stop = true;
-        furi_timer_stop(fhttp.get_timeout_timer);
-        break;
-    case ActionPrev:
-        // delete message
-        app_instance->pre_saved_messages.messages[app_instance->pre_saved_messages.index] = NULL;
-
-        for(uint32_t i = app_instance->pre_saved_messages.index;
-            i < app_instance->pre_saved_messages.count - 1;
-            i++) {
-            app_instance->pre_saved_messages.messages[i] =
-                app_instance->pre_saved_messages.messages[i + 1];
-        }
-        app_instance->pre_saved_messages.count--;
-
-        // add the item to the submenu
-        submenu_reset(app_instance->submenu_compose);
-
-        submenu_add_item(
-            app_instance->submenu_compose,
-            "Add Pre-Save",
-            FlipSocialSubmenuComposeIndexAddPreSave,
-            flip_social_callback_submenu_choices,
-            app_instance);
-
-        for(uint32_t i = 0; i < app_instance->pre_saved_messages.count; i++) {
-            submenu_add_item(
-                app_instance->submenu_compose,
-                app_instance->pre_saved_messages.messages[i],
-                FlipSocialSubemnuComposeIndexStartIndex + i,
-                flip_social_callback_submenu_choices,
-                app_instance);
-        }
-
-        // save playlist
-        save_playlist(&app_instance->pre_saved_messages);
-
-        flip_social_dialog_stop = true;
-        break;
-    default:
-        action = ActionNone;
-        break;
-    }
-
-    if(flip_social_dialog_stop) {
-        furi_pubsub_unsubscribe(app_instance->input_event_queue, app_instance->input_event);
-        flip_social_dialog_shown = false;
-        flip_social_dialog_stop = false;
-        if(action == ActionNext) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "Sent successfully!");
-            canvas_draw_str(canvas, 0, 50, "Loading feed :D");
-            canvas_draw_str(canvas, 0, 60, "Please wait...");
-            action = ActionNone;
-            if(flipper_http_process_response_async(
-                   flip_social_get_feed, flip_social_parse_json_feed)) {
-                view_dispatcher_switch_to_view(
-                    app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
-            } else {
-                // Set failure FlipSocialFeed object
-                if(!flip_social_temp_feed()) {
-                    return;
-                }
-                view_dispatcher_switch_to_view(
-                    app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
-            }
-        } else if(action == ActionBack) {
-            action = ActionNone;
-            view_dispatcher_switch_to_view(
-                app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-        } else {
-            action = ActionNone;
-            view_dispatcher_switch_to_view(
-                app_instance->view_dispatcher, FlipSocialViewLoggedInCompose);
-        }
-    }
-}
-// function to draw the dialog canvas
-void flip_social_canvas_draw_message(
-    Canvas* canvas,
-    char* user_username,
-    char* user_message,
-    bool is_flipped,
-    bool show_prev,
-    bool show_next,
-    int flip_count) {
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, user_username);
-    canvas_set_font(canvas, FontSecondary);
-
-    char flip_count_str[12];
-    if(flip_count == 1) {
-        snprintf(flip_count_str, sizeof(flip_count_str), "%d Flip", flip_count);
-        canvas_draw_str_aligned(canvas, 106, 54, AlignLeft, AlignTop, flip_count_str);
-    } else {
-        snprintf(flip_count_str, sizeof(flip_count_str), "%d Flips", flip_count);
-
-        if(flip_count < 10) {
-            canvas_draw_str_aligned(canvas, 100, 54, AlignLeft, AlignTop, flip_count_str);
-        } else if(flip_count < 100) {
-            canvas_draw_str_aligned(canvas, 94, 54, AlignLeft, AlignTop, flip_count_str);
-        } else {
-            canvas_draw_str_aligned(canvas, 88, 54, AlignLeft, AlignTop, flip_count_str);
-        }
-    }
-
-    draw_user_message(canvas, user_message, 0, 12);
-
-    // combine and shift icons/labels around if not show_prev or show_next
-    if(show_prev && show_next && !is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Prev");
-        canvas_draw_icon(canvas, 30, 54, &I_ButtonRight_4x7);
-        canvas_draw_str_aligned(canvas, 36, 54, AlignLeft, AlignTop, "Next");
-        canvas_draw_icon(canvas, 58, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 67, 54, AlignLeft, AlignTop, "Flip");
-    } else if(show_prev && !show_next && !is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Prev");
-        canvas_draw_icon(canvas, 28, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 37, 54, AlignLeft, AlignTop, "Flip");
-    } else if(!show_prev && show_next && !is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonRight_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Next");
-        canvas_draw_icon(canvas, 28, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 37, 54, AlignLeft, AlignTop, "Flip");
-    } else if(show_prev && show_next && is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Prev");
-        canvas_draw_icon(canvas, 28, 54, &I_ButtonRight_4x7);
-        canvas_draw_str_aligned(canvas, 34, 54, AlignLeft, AlignTop, "Next");
-        canvas_draw_icon(canvas, 54, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 63, 54, AlignLeft, AlignTop, "UnFlip");
-    } else if(show_prev && !show_next && is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Prev");
-        canvas_draw_icon(canvas, 28, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 37, 54, AlignLeft, AlignTop, "UnFlip");
-    } else if(!show_prev && show_next && is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonRight_4x7);
-        canvas_draw_str_aligned(canvas, 6, 54, AlignLeft, AlignTop, "Next");
-        canvas_draw_icon(canvas, 28, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 37, 54, AlignLeft, AlignTop, "UnFlip");
-    } else if(!show_prev && !show_next && is_flipped) {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 9, 54, AlignLeft, AlignTop, "UnFlip");
-    } else {
-        canvas_draw_icon(canvas, 0, 54, &I_ButtonOK_7x7);
-        canvas_draw_str_aligned(canvas, 9, 54, AlignLeft, AlignTop, "Flip");
-    }
-}
-// Callback function to handle the feed dialog
-void flip_social_callback_draw_feed(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-    if(!app_instance) {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
-    }
-
-    if(!flip_social_dialog_shown) {
-        flip_social_dialog_shown = true;
-        app_instance->input_event_queue = furi_record_open(RECORD_INPUT_EVENTS);
-        app_instance->input_event =
-            furi_pubsub_subscribe(app_instance->input_event_queue, on_input, NULL);
-        auth_headers_alloc();
-    }
-
-    // handle action
-    switch(action) {
-    case ActionNone:
-        flip_social_canvas_draw_message(
-            canvas,
-            flip_social_feed->usernames[flip_social_feed->index],
-            flip_social_feed->messages[flip_social_feed->index],
-            flip_social_feed->is_flipped[flip_social_feed->index],
-            flip_social_feed->index > 0,
-            flip_social_feed->index < flip_social_feed->count - 1,
-            flip_social_feed->flips[flip_social_feed->index]);
-        break;
-    case ActionNext:
-        canvas_clear(canvas);
-        if(flip_social_feed->index < flip_social_feed->count - 1) {
-            flip_social_feed->index++;
-        }
-        flip_social_canvas_draw_message(
-            canvas,
-            flip_social_feed->usernames[flip_social_feed->index],
-            flip_social_feed->messages[flip_social_feed->index],
-            flip_social_feed->is_flipped[flip_social_feed->index],
-            flip_social_feed->index > 0,
-            flip_social_feed->index < flip_social_feed->count - 1,
-            flip_social_feed->flips[flip_social_feed->index]);
-        action = ActionNone;
-        break;
-    case ActionPrev:
-        canvas_clear(canvas);
-        if(flip_social_feed->index > 0) {
-            flip_social_feed->index--;
-        }
-        flip_social_canvas_draw_message(
-            canvas,
-            flip_social_feed->usernames[flip_social_feed->index],
-            flip_social_feed->messages[flip_social_feed->index],
-            flip_social_feed->is_flipped[flip_social_feed->index],
-            flip_social_feed->index > 0,
-            flip_social_feed->index < flip_social_feed->count - 1,
-            flip_social_feed->flips[flip_social_feed->index]);
-        action = ActionNone;
-        break;
-    case ActionFlip:
-        canvas_clear(canvas);
-        // Moved to above the is_flipped check
-        if(!flip_social_feed->is_flipped[flip_social_feed->index]) {
-            // increase the flip count
-            flip_social_feed->flips[flip_social_feed->index]++;
-        } else {
-            // decrease the flip count
-            flip_social_feed->flips[flip_social_feed->index]--;
-        }
-        // change the flip status
-        flip_social_feed->is_flipped[flip_social_feed->index] =
-            !flip_social_feed->is_flipped[flip_social_feed->index];
-        // send post request to flip the message
-        if(app_instance->login_username_logged_in == NULL) {
-            FURI_LOG_E(TAG, "Username is NULL");
-            return;
-        }
-        char payload[256];
-        snprintf(
-            payload,
-            sizeof(payload),
-            "{\"username\":\"%s\",\"post_id\":\"%u\"}",
-            app_instance->login_username_logged_in,
-            flip_social_feed->ids[flip_social_feed->index]);
-        flipper_http_post_request_with_headers(
-            "https://www.flipsocial.net/api/feed/flip/", auth_headers, payload);
-        flip_social_canvas_draw_message(
-            canvas,
-            flip_social_feed->usernames[flip_social_feed->index],
-            flip_social_feed->messages[flip_social_feed->index],
-            flip_social_feed->is_flipped[flip_social_feed->index],
-            flip_social_feed->index > 0,
-            flip_social_feed->index < flip_social_feed->count - 1,
-            flip_social_feed->flips[flip_social_feed->index]);
-        action = ActionNone;
-        break;
-    case ActionBack:
-        canvas_clear(canvas);
-        flip_social_dialog_stop = true;
-        flip_social_feed->index = 0;
-        action = ActionNone;
-        break;
-    default:
-        break;
-    }
-
-    if(flip_social_dialog_stop) {
-        furi_pubsub_unsubscribe(app_instance->input_event_queue, app_instance->input_event);
-        flip_social_dialog_shown = false;
-        flip_social_dialog_stop = false;
-        action = ActionNone;
-    }
-}
-/**
- * @brief Navigation callback for asynchonously handling the login process.
- * @param canvas The canvas to draw on.
- * @param model The model - unused
- * @return void
- */
-void flip_social_callback_draw_login(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-
-    canvas_set_font(canvas, FontSecondary);
-
-    if(!flip_social_board_is_active(canvas)) {
-        return;
-    }
-
-    canvas_draw_str(canvas, 0, 7, "Logging in...");
-
-    // Perform login request
-    if(!flip_social_sent_login_request) {
-        if(!app_instance->login_username_logged_out || !app_instance->login_password_logged_out ||
-           strlen(app_instance->login_username_logged_out) == 0 ||
-           strlen(app_instance->login_password_logged_out) == 0) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "Please enter your credentials.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-            return;
-        }
-
-        flip_social_sent_login_request = true;
-
-        char buffer[256];
-        snprintf(
-            buffer,
-            sizeof(buffer),
-            "{\"username\":\"%s\",\"password\":\"%s\"}",
-            app_instance->login_username_logged_out,
-            app_instance->login_password_logged_out);
-        auth_headers_alloc();
-        flip_social_login_success = flipper_http_post_request_with_headers(
-            "https://www.flipsocial.net/api/user/login/", auth_headers, buffer);
-        if(flip_social_login_success) {
-            fhttp.state = RECEIVING;
-            return;
-        } else {
-            fhttp.state = ISSUE;
-            return;
-        }
-    }
-    // handle response
-    if(flip_social_sent_login_request && flip_social_login_success) {
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(canvas, 0, 17, "Request Sent!");
-        canvas_draw_str(canvas, 0, 32, "Awaiting reponse...");
-
-        if(fhttp.state == IDLE && fhttp.last_response != NULL) {
-            // read response
-            if(strstr(fhttp.last_response, "[SUCCESS]") != NULL ||
-               strstr(fhttp.last_response, "User found") != NULL) {
-                canvas_draw_str(canvas, 0, 42, "Login successful!");
-                canvas_draw_str(canvas, 0, 62, "Welcome back!");
-
-                app_instance->is_logged_in = "true";
-
-                // set the logged_in_username and change_password_logged_in
-                if(app_instance->login_username_logged_out) {
-                    strcpy(
-                        app_instance->login_username_logged_in,
-                        app_instance->login_username_logged_out);
-                }
-                if(app_instance->login_password_logged_out) {
-                    app_instance->change_password_logged_in =
-                        app_instance->login_password_logged_out;
-                }
-
-                save_settings(
-                    app_instance->wifi_ssid_logged_out,
-                    app_instance->wifi_password_logged_out,
-                    app_instance->login_username_logged_out,
-                    app_instance->login_username_logged_in,
-                    app_instance->login_password_logged_out,
-                    app_instance->change_password_logged_in,
-                    app_instance->is_logged_in);
-
-                // send user to the logged in submenu
-                view_dispatcher_switch_to_view(
-                    app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-            } else if(strstr(fhttp.last_response, "User not found") != NULL) {
-                canvas_clear(canvas);
-                canvas_draw_str(canvas, 0, 10, "Account not found...");
-                canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-            } else {
-                flip_social_handle_error(canvas);
-            }
-        } else if((fhttp.state == ISSUE || fhttp.state == INACTIVE) && fhttp.last_response != NULL) {
-            flip_social_handle_error(canvas);
-        } else if(fhttp.state == IDLE && fhttp.last_response == NULL) {
-            flip_social_handle_error(canvas);
-        }
-    } else if(flip_social_sent_login_request && !flip_social_login_success) {
-        canvas_clear(canvas);
-        canvas_draw_str(canvas, 0, 10, "Failed sending request.");
-        canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-        canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-    }
-}
-
-/**
- * @brief Navigation callback for asynchonously handling the register process.
- * @param canvas The canvas to draw on.
- * @param model The model - unused
- * @return void
- */
-void flip_social_callback_draw_register(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-
-    canvas_set_font(canvas, FontSecondary);
-
-    if(!flip_social_board_is_active(canvas)) {
-        return;
-    }
-
-    canvas_draw_str(canvas, 0, 7, "Registering...");
-
-    // Perform login request
-    if(!flip_social_sent_register_request) {
-        // check if the username and password are valid
-        if(!app_instance->register_username_logged_out ||
-           !app_instance->register_password_logged_out ||
-           strlen(app_instance->register_username_logged_out) == 0 ||
-           strlen(app_instance->register_password_logged_out) == 0) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "Please enter your credentials.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-            return;
-        }
-
-        // check if both passwords match
-        if(strcmp(
-               app_instance->register_password_logged_out,
-               app_instance->register_password_2_logged_out) != 0) {
-            canvas_clear(canvas);
-            canvas_draw_str(canvas, 0, 10, "Passwords do not match.");
-            canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-            return;
-        }
-
-        char buffer[128];
-        snprintf(
-            buffer,
-            sizeof(buffer),
-            "{\"username\":\"%s\",\"password\":\"%s\"}",
-            app_instance->register_username_logged_out,
-            app_instance->register_password_logged_out);
-        flip_social_register_success = flipper_http_post_request_with_headers(
-            "https://www.flipsocial.net/api/user/register/",
-            "{\"Content-Type\":\"application/json\"}",
-            buffer);
-
-        flip_social_sent_register_request = true;
-        if(flip_social_register_success) {
-            // Set the state to RECEIVING to ensure we continue to see the receiving message
-            fhttp.state = RECEIVING;
-        } else {
-            fhttp.state = ISSUE;
-        }
-    }
-    // handle response
-    if(flip_social_sent_register_request && flip_social_register_success) {
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(canvas, 0, 17, "Request Sent!");
-        canvas_draw_str(canvas, 0, 32, "Awaiting reponse...");
-
-        if(fhttp.state == IDLE) {
-            // read response
-            if(fhttp.last_response != NULL &&
-               (strstr(fhttp.last_response, "[SUCCESS]") != NULL ||
-                strstr(fhttp.last_response, "User created") != NULL)) {
-                canvas_draw_str(canvas, 0, 42, "Registeration successful!");
-                canvas_draw_str(canvas, 0, 62, "Welcome to FlipSocial!");
-
-                // set the login credentials
-                if(app_instance->login_username_logged_out) {
-                    app_instance->login_username_logged_out =
-                        app_instance->register_username_logged_out;
-                }
-                if(app_instance->login_password_logged_out) {
-                    app_instance->login_password_logged_out =
-                        app_instance->register_password_logged_out;
-                    app_instance->change_password_logged_in =
-                        app_instance->register_password_logged_out;
-                }
-                if(app_instance->login_username_logged_in) {
-                    app_instance->login_username_logged_in =
-                        app_instance->register_username_logged_out;
-                }
-
-                app_instance->is_logged_in = "true";
-
-                // update header credentials
-                auth_headers_alloc();
-
-                // save the credentials
-                save_settings(
-                    app_instance->wifi_ssid_logged_out,
-                    app_instance->wifi_password_logged_out,
-                    app_instance->login_username_logged_out,
-                    app_instance->login_username_logged_in,
-                    app_instance->login_password_logged_out,
-                    app_instance->change_password_logged_in,
-                    app_instance->is_logged_in);
-
-                // send user to the logged in submenu
-                view_dispatcher_switch_to_view(
-                    app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
-            } else if(strstr(fhttp.last_response, "Username or password not provided") != NULL) {
-                canvas_clear(canvas);
-                canvas_draw_str(canvas, 0, 10, "Please enter your credentials.");
-                canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
-            } else if(
-                strstr(fhttp.last_response, "User already exists") != NULL ||
-                strstr(fhttp.last_response, "Multiple users found") != NULL) {
-                canvas_draw_str(canvas, 0, 42, "Registration failed...");
-                canvas_draw_str(canvas, 0, 52, "Username already exists.");
-                canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-            } else {
-                canvas_draw_str(canvas, 0, 42, "Registration failed...");
-                canvas_draw_str(canvas, 0, 52, "Update your credentials.");
-                canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-            }
-        } else if(fhttp.state == ISSUE || fhttp.state == INACTIVE) {
-            flip_social_handle_error(canvas);
-        }
-    } else if(flip_social_sent_register_request && !flip_social_register_success) {
-        canvas_clear(canvas);
-        canvas_draw_str(canvas, 0, 10, "Failed sending request.");
-        canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
-        canvas_draw_str(canvas, 0, 62, "Press BACK to return.");
-    }
-}
-
-// function to draw the dialog canvas
-void flip_social_canvas_draw_explore(Canvas* canvas, char* user_username, char* content) {
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, user_username);
-    canvas_set_font(canvas, FontSecondary);
-
-    draw_user_message(canvas, content, 0, 12);
-
-    canvas_set_font(canvas, FontSecondary);
-    canvas_draw_icon(canvas, 0, 53, &I_ButtonLeft_4x7);
-    canvas_draw_str_aligned(canvas, 9, 54, AlignLeft, AlignTop, "Remove");
-    canvas_draw_icon(canvas, 98, 53, &I_ButtonRight_4x7);
-    canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Add");
-
-    if(strlen(content) > 0) {
-        last_explore_response = content;
-    }
-}
-
-// Callback function to handle the explore dialog
-void flip_social_callback_draw_explore(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-    if(!app_instance) {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
-    }
-
-    if(!flip_social_dialog_shown) {
-        flip_social_dialog_shown = true;
-        app_instance->input_event_queue = furi_record_open(RECORD_INPUT_EVENTS);
-        app_instance->input_event =
-            furi_pubsub_subscribe(app_instance->input_event_queue, on_input, NULL);
-        auth_headers_alloc();
-    }
-    flip_social_canvas_draw_explore(
-        canvas, flip_social_explore->usernames[flip_social_explore->index], last_explore_response);
-
-    // handle action
-    switch(action) {
-    case ActionNext:
-        // add friend
-        char add_payload[128];
-        snprintf(
-            add_payload,
-            sizeof(add_payload),
-            "{\"username\":\"%s\",\"friend\":\"%s\"}",
-            app_instance->login_username_logged_in,
-            flip_social_explore->usernames[flip_social_explore->index]);
-        flipper_http_post_request_with_headers(
-            "https://www.flipsocial.net/api/user/add-friend/", auth_headers, add_payload);
-        canvas_clear(canvas);
-        flip_social_canvas_draw_explore(
-            canvas, flip_social_explore->usernames[flip_social_explore->index], "Added!");
-        action = ActionNone;
-        break;
-    case ActionPrev:
-        // remove friend
-        char remove_payload[128];
-        snprintf(
-            remove_payload,
-            sizeof(remove_payload),
-            "{\"username\":\"%s\",\"friend\":\"%s\"}",
-            app_instance->login_username_logged_in,
-            flip_social_explore->usernames[flip_social_explore->index]);
-        flipper_http_post_request_with_headers(
-            "https://www.flipsocial.net/api/user/remove-friend/", auth_headers, remove_payload);
-        canvas_clear(canvas);
-        flip_social_canvas_draw_explore(
-            canvas, flip_social_explore->usernames[flip_social_explore->index], "Removed!");
-        action = ActionNone;
-        break;
-    case ActionBack:
-        canvas_clear(canvas);
-        flip_social_dialog_stop = true;
-        last_explore_response = "";
-        flip_social_dialog_shown = false;
-        flip_social_explore->index = 0;
-        action = ActionNone;
-        break;
-    default:
-        break;
-    }
-
-    if(flip_social_dialog_stop) {
-        furi_pubsub_unsubscribe(app_instance->input_event_queue, app_instance->input_event);
-        flip_social_dialog_shown = false;
-        flip_social_dialog_stop = false;
-        action = ActionNone;
-    }
-}
-
-// Callback function to handle the friends dialog
-void flip_social_callback_draw_friends(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-    if(!app_instance) {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
-    }
-
-    if(!flip_social_dialog_shown) {
-        flip_social_dialog_shown = true;
-        app_instance->input_event_queue = furi_record_open(RECORD_INPUT_EVENTS);
-        app_instance->input_event =
-            furi_pubsub_subscribe(app_instance->input_event_queue, on_input, NULL);
-        auth_headers_alloc();
-    }
-    flip_social_canvas_draw_explore(
-        canvas, flip_social_friends->usernames[flip_social_friends->index], last_explore_response);
-
-    // handle action
-    switch(action) {
-    case ActionNext:
-        // add friend
-        char add_payload[128];
-        snprintf(
-            add_payload,
-            sizeof(add_payload),
-            "{\"username\":\"%s\",\"friend\":\"%s\"}",
-            app_instance->login_username_logged_in,
-            flip_social_friends->usernames[flip_social_friends->index]);
-        if(flipper_http_post_request_with_headers(
-               "https://www.flipsocial.net/api/user/add-friend/", auth_headers, add_payload)) {
-            canvas_clear(canvas);
-            flip_social_canvas_draw_explore(
-                canvas, flip_social_friends->usernames[flip_social_friends->index], "Added!");
-
-            // add the friend to the friends list
-            flip_social_friends->usernames[flip_social_friends->count] =
-                flip_social_friends->usernames[flip_social_friends->index];
-            flip_social_friends->count++;
-            if(!flip_social_update_friends()) {
-                FURI_LOG_E(TAG, "Failed to update friends");
-            }
-        }
-        action = ActionNone;
-        break;
-    case ActionPrev:
-        // remove friend
-        char remove_payload[128];
-        snprintf(
-            remove_payload,
-            sizeof(remove_payload),
-            "{\"username\":\"%s\",\"friend\":\"%s\"}",
-            app_instance->login_username_logged_in,
-            flip_social_friends->usernames[flip_social_friends->index]);
-        if(flipper_http_post_request_with_headers(
-               "https://www.flipsocial.net/api/user/remove-friend/",
-               auth_headers,
-               remove_payload)) {
-            canvas_clear(canvas);
-            flip_social_canvas_draw_explore(
-                canvas, flip_social_friends->usernames[flip_social_friends->index], "Removed!");
-
-            // remove the friend from the friends list
-            for(int i = flip_social_friends->index; i < flip_social_friends->count - 1; i++) {
-                flip_social_friends->usernames[i] = flip_social_friends->usernames[i + 1];
-            }
-            flip_social_friends->count--;
-            if(!flip_social_update_friends()) {
-                FURI_LOG_E(TAG, "Failed to update friends");
-            }
-        }
-        action = ActionNone;
-        break;
-    case ActionBack:
-        canvas_clear(canvas);
-        flip_social_dialog_stop = true;
-        last_explore_response = "";
-        flip_social_dialog_shown = false;
-        flip_social_friends->index = 0;
-        action = ActionNone;
-        break;
-    default:
-        break;
-    }
-
-    if(flip_social_dialog_stop) {
-        furi_pubsub_unsubscribe(app_instance->input_event_queue, app_instance->input_event);
-        flip_social_dialog_shown = false;
-        flip_social_dialog_stop = false;
-        action = ActionNone;
-    }
-}
-
-void flip_social_canvas_draw_user_message(
-    Canvas* canvas,
-    char* user_username,
-    char* user_message,
-    bool show_prev,
-    bool show_next) {
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, user_username);
-    canvas_set_font(canvas, FontSecondary);
-
-    draw_user_message(canvas, user_message, 0, 12);
-
-    canvas_set_font(canvas, FontSecondary);
-    if(show_prev) {
-        canvas_draw_icon(canvas, 0, 53, &I_ButtonLeft_4x7);
-        canvas_draw_str_aligned(canvas, 9, 54, AlignLeft, AlignTop, "Prev");
-    }
-
-    canvas_draw_icon(canvas, 47, 53, &I_ButtonOK_7x7);
-    canvas_draw_str_aligned(canvas, 56, 54, AlignLeft, AlignTop, "Create");
-
-    if(show_next) {
-        canvas_draw_icon(canvas, 98, 53, &I_ButtonRight_4x7);
-        canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Next");
-    }
-}
-
-// Callback function to handle the messages dialog
-void flip_social_callback_draw_messages(Canvas* canvas, void* model) {
-    UNUSED(model);
-    if(!canvas) {
-        FURI_LOG_E(TAG, "Canvas is NULL");
-        return;
-    }
-    if(!app_instance) {
-        FURI_LOG_E(TAG, "FlipSocialApp is NULL");
-        return;
-    }
-
-    if(!flip_social_dialog_shown) {
-        flip_social_dialog_shown = true;
-        app_instance->input_event_queue = furi_record_open(RECORD_INPUT_EVENTS);
-        app_instance->input_event =
-            furi_pubsub_subscribe(app_instance->input_event_queue, on_input, NULL);
-    }
-
-    // handle action
-    switch(action) {
-    case ActionNone:
-        flip_social_canvas_draw_user_message(
-            canvas,
-            flip_social_messages->usernames[flip_social_messages->index],
-            flip_social_messages->messages[flip_social_messages->index],
-            flip_social_messages->index > 0,
-            flip_social_messages->index < flip_social_messages->count - 1);
-        action = ActionNone;
-        break;
-    case ActionNext:
-        // view next message (if any)
-        canvas_clear(canvas);
-        if(flip_social_messages->index < flip_social_messages->count - 1) {
-            flip_social_messages->index++;
-        }
-        flip_social_canvas_draw_user_message(
-            canvas,
-            flip_social_messages->usernames[flip_social_messages->index],
-            flip_social_messages->messages[flip_social_messages->index],
-            flip_social_messages->index > 0,
-            flip_social_messages->index < flip_social_messages->count - 1);
-        action = ActionNone;
-        break;
-    case ActionPrev:
-        // view previous message (if any)
-        canvas_clear(canvas);
-        if(flip_social_messages->index > 0) {
-            flip_social_messages->index--;
-        }
-        flip_social_canvas_draw_user_message(
-            canvas,
-            flip_social_messages->usernames[flip_social_messages->index],
-            flip_social_messages->messages[flip_social_messages->index],
-            flip_social_messages->index > 0,
-            flip_social_messages->index < flip_social_messages->count - 1);
-        action = ActionNone;
-        break;
-    case ActionBack:
-        //  go back to the previous view
-        flip_social_dialog_stop = true;
-        action = ActionNone;
-        break;
-    case ActionFlip:
-        // go to the input view
-        flip_social_dialog_stop = true;
-        flip_social_send_message = true;
-        action = ActionNone;
-        break;
-    default:
-        action = ActionNone;
-        break;
-    }
-
-    if(flip_social_dialog_stop && flip_social_dialog_shown) {
-        furi_pubsub_unsubscribe(app_instance->input_event_queue, app_instance->input_event);
-        flip_social_dialog_shown = false;
-        flip_social_dialog_stop = false;
-        if(flip_social_send_message) {
-            FURI_LOG_I(TAG, "Switching to new message input view");
-            action = ActionNone;
-            flip_social_send_message = false;
-            view_dispatcher_switch_to_view(
-                app_instance->view_dispatcher, FlipSocialViewLoggedInMessagesNewMessageInput);
-        } else {
-            action = ActionNone;
-            view_dispatcher_switch_to_view(
-                app_instance->view_dispatcher, FlipSocialViewLoggedInMessagesSubmenu);
-        }
-    }
-}

+ 0 - 71
flip_social/draw/flip_social_draw.h

@@ -1,71 +0,0 @@
-#ifndef FLIP_SOCIAL_DRAW_H
-#define FLIP_SOCIAL_DRAW_H
-#include <flip_social.h>
-#include <flip_storage/flip_social_storage.h>
-#include <callback/flip_social_callback.h>
-#include <friends/flip_social_friends.h>
-
-typedef enum {
-    ActionNone,
-    ActionBack,
-    ActionNext,
-    ActionPrev,
-    ActionFlip,
-} Action;
-
-extern Action action;
-
-bool flip_social_board_is_active(Canvas* canvas);
-
-void flip_social_handle_error(Canvas* canvas);
-
-void on_input(const void* event, void* ctx);
-// Function to draw the message on the canvas with word wrapping
-void draw_user_message(Canvas* canvas, const char* user_message, int x, int y);
-
-void flip_social_callback_draw_compose(Canvas* canvas, void* model);
-// function to draw the dialog canvas
-void flip_social_canvas_draw_message(
-    Canvas* canvas,
-    char* user_username,
-    char* user_message,
-    bool is_flipped,
-    bool show_prev,
-    bool show_next,
-    int flip_count);
-// Callback function to handle the feed dialog
-void flip_social_callback_draw_feed(Canvas* canvas, void* model);
-/**
- * @brief Navigation callback for asynchonously handling the login process.
- * @param canvas The canvas to draw on.
- * @param model The model - unused
- * @return void
- */
-void flip_social_callback_draw_login(Canvas* canvas, void* model);
-/**
- * @brief Navigation callback for asynchonously handling the register process.
- * @param canvas The canvas to draw on.
- * @param model The model - unused
- * @return void
- */
-void flip_social_callback_draw_register(Canvas* canvas, void* model);
-
-// function to draw the dialog canvas
-void flip_social_canvas_draw_explore(Canvas* canvas, char* user_username, char* content);
-
-// Callback function to handle the explore dialog
-void flip_social_callback_draw_explore(Canvas* canvas, void* model);
-
-// Callback function to handle the friends dialog
-void flip_social_callback_draw_friends(Canvas* canvas, void* model);
-
-void flip_social_canvas_draw_user_message(
-    Canvas* canvas,
-    char* user_username,
-    char* user_message,
-    bool show_prev,
-    bool show_next);
-// Callback function to handle the messages dialog
-void flip_social_callback_draw_messages(Canvas* canvas, void* model);
-
-#endif

+ 198 - 139
flip_social/easy_flipper/easy_flipper.c

@@ -5,9 +5,11 @@
  * @param context The context - unused
  * @return next view id (VIEW_NONE to exit the app)
  */
-uint32_t easy_flipper_callback_exit_app(void* context) {
+uint32_t easy_flipper_callback_exit_app(void *context)
+{
     // Exit the application
-    if(!context) {
+    if (!context)
+    {
         FURI_LOG_E(EASY_TAG, "Context is NULL");
         return VIEW_NONE;
     }
@@ -21,13 +23,16 @@ uint32_t easy_flipper_callback_exit_app(void* context) {
  * @param buffer_size The size of the buffer
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_buffer(char** buffer, uint32_t buffer_size) {
-    if(!buffer) {
+bool easy_flipper_set_buffer(char **buffer, uint32_t buffer_size)
+{
+    if (!buffer)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_buffer");
         return false;
     }
-    *buffer = (char*)malloc(buffer_size);
-    if(!*buffer) {
+    *buffer = (char *)malloc(buffer_size);
+    if (!*buffer)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate buffer");
         return false;
     }
@@ -46,32 +51,39 @@ bool easy_flipper_set_buffer(char** buffer, uint32_t buffer_size) {
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_view(
-    View** view,
+    View **view,
     int32_t view_id,
-    void draw_callback(Canvas*, void*),
-    bool input_callback(InputEvent*, void*),
-    uint32_t (*previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!view || !view_dispatcher) {
+    void draw_callback(Canvas *, void *),
+    bool input_callback(InputEvent *, void *),
+    uint32_t (*previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!view || !view_dispatcher)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_view");
         return false;
     }
     *view = view_alloc();
-    if(!*view) {
+    if (!*view)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate View");
         return false;
     }
-    if(draw_callback) {
+    if (draw_callback)
+    {
         view_set_draw_callback(*view, draw_callback);
     }
-    if(input_callback) {
+    if (input_callback)
+    {
         view_set_input_callback(*view, input_callback);
     }
-    if(context) {
+    if (context)
+    {
         view_set_context(*view, context);
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(*view, previous_callback);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, *view);
@@ -85,18 +97,22 @@ bool easy_flipper_set_view(
  * @param context The context to pass to the event callback
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_view_dispatcher(ViewDispatcher** view_dispatcher, Gui* gui, void* context) {
-    if(!view_dispatcher) {
+bool easy_flipper_set_view_dispatcher(ViewDispatcher **view_dispatcher, Gui *gui, void *context)
+{
+    if (!view_dispatcher)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_view_dispatcher");
         return false;
     }
     *view_dispatcher = view_dispatcher_alloc();
-    if(!*view_dispatcher) {
+    if (!*view_dispatcher)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate ViewDispatcher");
         return false;
     }
     view_dispatcher_attach_to_gui(*view_dispatcher, gui, ViewDispatcherTypeFullscreen);
-    if(context) {
+    if (context)
+    {
         view_dispatcher_set_event_callback_context(*view_dispatcher, context);
     }
     return true;
@@ -113,24 +129,29 @@ bool easy_flipper_set_view_dispatcher(ViewDispatcher** view_dispatcher, Gui* gui
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_submenu(
-    Submenu** submenu,
+    Submenu **submenu,
     int32_t view_id,
-    char* title,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher) {
-    if(!submenu) {
+    char *title,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher)
+{
+    if (!submenu)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_submenu");
         return false;
     }
     *submenu = submenu_alloc();
-    if(!*submenu) {
+    if (!*submenu)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate Submenu");
         return false;
     }
-    if(title) {
+    if (title)
+    {
         submenu_set_header(*submenu, title);
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(submenu_get_view(*submenu), previous_callback);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, submenu_get_view(*submenu));
@@ -147,20 +168,24 @@ bool easy_flipper_set_submenu(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_menu(
-    Menu** menu,
+    Menu **menu,
     int32_t view_id,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher) {
-    if(!menu) {
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher)
+{
+    if (!menu)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_menu");
         return false;
     }
     *menu = menu_alloc();
-    if(!*menu) {
+    if (!*menu)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate Menu");
         return false;
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(menu_get_view(*menu), previous_callback);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, menu_get_view(*menu));
@@ -177,24 +202,29 @@ bool easy_flipper_set_menu(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_widget(
-    Widget** widget,
+    Widget **widget,
     int32_t view_id,
-    char* text,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher) {
-    if(!widget) {
+    char *text,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher)
+{
+    if (!widget)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_widget");
         return false;
     }
     *widget = widget_alloc();
-    if(!*widget) {
+    if (!*widget)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate Widget");
         return false;
     }
-    if(text) {
+    if (text)
+    {
         widget_add_text_scroll_element(*widget, 0, 0, 128, 64, text);
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(widget_get_view(*widget), previous_callback);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, widget_get_view(*widget));
@@ -213,30 +243,33 @@ bool easy_flipper_set_widget(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_variable_item_list(
-    VariableItemList** variable_item_list,
+    VariableItemList **variable_item_list,
     int32_t view_id,
-    void (*enter_callback)(void*, uint32_t),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!variable_item_list) {
+    void (*enter_callback)(void *, uint32_t),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!variable_item_list)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_variable_item_list");
         return false;
     }
     *variable_item_list = variable_item_list_alloc();
-    if(!*variable_item_list) {
+    if (!*variable_item_list)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate VariableItemList");
         return false;
     }
-    if(enter_callback) {
+    if (enter_callback)
+    {
         variable_item_list_set_enter_callback(*variable_item_list, enter_callback, context);
     }
-    if(previous_callback) {
-        view_set_previous_callback(
-            variable_item_list_get_view(*variable_item_list), previous_callback);
+    if (previous_callback)
+    {
+        view_set_previous_callback(variable_item_list_get_view(*variable_item_list), previous_callback);
     }
-    view_dispatcher_add_view(
-        *view_dispatcher, view_id, variable_item_list_get_view(*variable_item_list));
+    view_dispatcher_add_view(*view_dispatcher, view_id, variable_item_list_get_view(*variable_item_list));
     return true;
 }
 
@@ -249,38 +282,38 @@ bool easy_flipper_set_variable_item_list(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_text_input(
-    TextInput** text_input,
+    TextInput **text_input,
     int32_t view_id,
-    char* header_text,
-    char* text_input_temp_buffer,
+    char *header_text,
+    char *text_input_temp_buffer,
     uint32_t text_input_buffer_size,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!text_input) {
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!text_input)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_text_input");
         return false;
     }
     *text_input = text_input_alloc();
-    if(!*text_input) {
+    if (!*text_input)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate TextInput");
         return false;
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(text_input_get_view(*text_input), previous_callback);
     }
-    if(header_text) {
+    if (header_text)
+    {
         text_input_set_header_text(*text_input, header_text);
     }
-    if(text_input_temp_buffer && text_input_buffer_size && result_callback) {
-        text_input_set_result_callback(
-            *text_input,
-            result_callback,
-            context,
-            text_input_temp_buffer,
-            text_input_buffer_size,
-            false);
+    if (text_input_temp_buffer && text_input_buffer_size && result_callback)
+    {
+        text_input_set_result_callback(*text_input, result_callback, context, text_input_temp_buffer, text_input_buffer_size, false);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, text_input_get_view(*text_input));
     return true;
@@ -295,38 +328,38 @@ bool easy_flipper_set_text_input(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_uart_text_input(
-    TextInput** uart_text_input,
+    TextInput **uart_text_input,
     int32_t view_id,
-    char* header_text,
-    char* uart_text_input_temp_buffer,
+    char *header_text,
+    char *uart_text_input_temp_buffer,
     uint32_t uart_text_input_buffer_size,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!uart_text_input) {
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!uart_text_input)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_uart_text_input");
         return false;
     }
     *uart_text_input = text_input_alloc();
-    if(!*uart_text_input) {
+    if (!*uart_text_input)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate UART_TextInput");
         return false;
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(text_input_get_view(*uart_text_input), previous_callback);
     }
-    if(header_text) {
+    if (header_text)
+    {
         text_input_set_header_text(*uart_text_input, header_text);
     }
-    if(uart_text_input_temp_buffer && uart_text_input_buffer_size && result_callback) {
-        text_input_set_result_callback(
-            *uart_text_input,
-            result_callback,
-            context,
-            uart_text_input_temp_buffer,
-            uart_text_input_buffer_size,
-            false);
+    if (uart_text_input_temp_buffer && uart_text_input_buffer_size && result_callback)
+    {
+        text_input_set_result_callback(*uart_text_input, result_callback, context, uart_text_input_temp_buffer, uart_text_input_buffer_size, false);
     }
     text_input_show_illegal_symbols(*uart_text_input, true);
     view_dispatcher_add_view(*view_dispatcher, view_id, text_input_get_view(*uart_text_input));
@@ -353,52 +386,63 @@ bool easy_flipper_set_uart_text_input(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_dialog_ex(
-    DialogEx** dialog_ex,
+    DialogEx **dialog_ex,
     int32_t view_id,
-    char* header,
+    char *header,
     uint16_t header_x,
     uint16_t header_y,
-    char* text,
+    char *text,
     uint16_t text_x,
     uint16_t text_y,
-    char* left_button_text,
-    char* right_button_text,
-    char* center_button_text,
-    void (*result_callback)(DialogExResult, void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!dialog_ex) {
+    char *left_button_text,
+    char *right_button_text,
+    char *center_button_text,
+    void (*result_callback)(DialogExResult, void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!dialog_ex)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_dialog_ex");
         return false;
     }
     *dialog_ex = dialog_ex_alloc();
-    if(!*dialog_ex) {
+    if (!*dialog_ex)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate DialogEx");
         return false;
     }
-    if(header) {
+    if (header)
+    {
         dialog_ex_set_header(*dialog_ex, header, header_x, header_y, AlignLeft, AlignTop);
     }
-    if(text) {
+    if (text)
+    {
         dialog_ex_set_text(*dialog_ex, text, text_x, text_y, AlignLeft, AlignTop);
     }
-    if(left_button_text) {
+    if (left_button_text)
+    {
         dialog_ex_set_left_button_text(*dialog_ex, left_button_text);
     }
-    if(right_button_text) {
+    if (right_button_text)
+    {
         dialog_ex_set_right_button_text(*dialog_ex, right_button_text);
     }
-    if(center_button_text) {
+    if (center_button_text)
+    {
         dialog_ex_set_center_button_text(*dialog_ex, center_button_text);
     }
-    if(result_callback) {
+    if (result_callback)
+    {
         dialog_ex_set_result_callback(*dialog_ex, result_callback);
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(dialog_ex_get_view(*dialog_ex), previous_callback);
     }
-    if(context) {
+    if (context)
+    {
         dialog_ex_set_context(*dialog_ex, context);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, dialog_ex_get_view(*dialog_ex));
@@ -422,40 +466,48 @@ bool easy_flipper_set_dialog_ex(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_popup(
-    Popup** popup,
+    Popup **popup,
     int32_t view_id,
-    char* header,
+    char *header,
     uint16_t header_x,
     uint16_t header_y,
-    char* text,
+    char *text,
     uint16_t text_x,
     uint16_t text_y,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context) {
-    if(!popup) {
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context)
+{
+    if (!popup)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_popup");
         return false;
     }
     *popup = popup_alloc();
-    if(!*popup) {
+    if (!*popup)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate Popup");
         return false;
     }
-    if(header) {
+    if (header)
+    {
         popup_set_header(*popup, header, header_x, header_y, AlignLeft, AlignTop);
     }
-    if(text) {
+    if (text)
+    {
         popup_set_text(*popup, text, text_x, text_y, AlignLeft, AlignTop);
     }
-    if(result_callback) {
+    if (result_callback)
+    {
         popup_set_callback(*popup, result_callback);
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(popup_get_view(*popup), previous_callback);
     }
-    if(context) {
+    if (context)
+    {
         popup_set_context(*popup, context);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, popup_get_view(*popup));
@@ -471,20 +523,24 @@ bool easy_flipper_set_popup(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_loading(
-    Loading** loading,
+    Loading **loading,
     int32_t view_id,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher) {
-    if(!loading) {
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher)
+{
+    if (!loading)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_loading");
         return false;
     }
     *loading = loading_alloc();
-    if(!*loading) {
+    if (!*loading)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate Loading");
         return false;
     }
-    if(previous_callback) {
+    if (previous_callback)
+    {
         view_set_previous_callback(loading_get_view(*loading), previous_callback);
     }
     view_dispatcher_add_view(*view_dispatcher, view_id, loading_get_view(*loading));
@@ -497,16 +553,19 @@ bool easy_flipper_set_loading(
  * @param buffer The buffer to copy the string to
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_char_to_furi_string(FuriString** furi_string, char* buffer) {
-    if(!furi_string) {
+bool easy_flipper_set_char_to_furi_string(FuriString **furi_string, char *buffer)
+{
+    if (!furi_string)
+    {
         FURI_LOG_E(EASY_TAG, "Invalid arguments provided to set_buffer_to_furi_string");
         return false;
     }
     *furi_string = furi_string_alloc();
-    if(!furi_string) {
+    if (!furi_string)
+    {
         FURI_LOG_E(EASY_TAG, "Failed to allocate FuriString");
         return false;
     }
     furi_string_set_str(*furi_string, buffer);
     return true;
-}
+}

+ 61 - 61
flip_social/easy_flipper/easy_flipper.h

@@ -28,14 +28,14 @@
  * @param context The context - unused
  * @return next view id (VIEW_NONE to exit the app)
  */
-uint32_t easy_flipper_callback_exit_app(void* context);
+uint32_t easy_flipper_callback_exit_app(void *context);
 /**
  * @brief Initialize a buffer
  * @param buffer The buffer to initialize
  * @param buffer_size The size of the buffer
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_buffer(char** buffer, uint32_t buffer_size);
+bool easy_flipper_set_buffer(char **buffer, uint32_t buffer_size);
 /**
  * @brief Initialize a View object
  * @param view The View object to initialize
@@ -47,13 +47,13 @@ bool easy_flipper_set_buffer(char** buffer, uint32_t buffer_size);
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_view(
-    View** view,
+    View **view,
     int32_t view_id,
-    void draw_callback(Canvas*, void*),
-    bool input_callback(InputEvent*, void*),
-    uint32_t (*previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    void draw_callback(Canvas *, void *),
+    bool input_callback(InputEvent *, void *),
+    uint32_t (*previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a ViewDispatcher object
@@ -62,7 +62,7 @@ bool easy_flipper_set_view(
  * @param context The context to pass to the event callback
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_view_dispatcher(ViewDispatcher** view_dispatcher, Gui* gui, void* context);
+bool easy_flipper_set_view_dispatcher(ViewDispatcher **view_dispatcher, Gui *gui, void *context);
 
 /**
  * @brief Initialize a Submenu object
@@ -75,11 +75,11 @@ bool easy_flipper_set_view_dispatcher(ViewDispatcher** view_dispatcher, Gui* gui
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_submenu(
-    Submenu** submenu,
+    Submenu **submenu,
     int32_t view_id,
-    char* title,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher);
+    char *title,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
 
 /**
  * @brief Initialize a Menu object
@@ -92,10 +92,10 @@ bool easy_flipper_set_submenu(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_menu(
-    Menu** menu,
+    Menu **menu,
     int32_t view_id,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher);
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
 
 /**
  * @brief Initialize a Widget object
@@ -107,11 +107,11 @@ bool easy_flipper_set_menu(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_widget(
-    Widget** widget,
+    Widget **widget,
     int32_t view_id,
-    char* text,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher);
+    char *text,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
 
 /**
  * @brief Initialize a VariableItemList object
@@ -125,12 +125,12 @@ bool easy_flipper_set_widget(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_variable_item_list(
-    VariableItemList** variable_item_list,
+    VariableItemList **variable_item_list,
     int32_t view_id,
-    void (*enter_callback)(void*, uint32_t),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    void (*enter_callback)(void *, uint32_t),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a TextInput object
@@ -141,15 +141,15 @@ bool easy_flipper_set_variable_item_list(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_text_input(
-    TextInput** text_input,
+    TextInput **text_input,
     int32_t view_id,
-    char* header_text,
-    char* text_input_temp_buffer,
+    char *header_text,
+    char *text_input_temp_buffer,
     uint32_t text_input_buffer_size,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a TextInput object with extra symbols
@@ -160,15 +160,15 @@ bool easy_flipper_set_text_input(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_uart_text_input(
-    TextInput** uart_text_input,
+    TextInput **uart_text_input,
     int32_t view_id,
-    char* header_text,
-    char* uart_text_input_temp_buffer,
+    char *header_text,
+    char *uart_text_input_temp_buffer,
     uint32_t uart_text_input_buffer_size,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a DialogEx object
@@ -190,21 +190,21 @@ bool easy_flipper_set_uart_text_input(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_dialog_ex(
-    DialogEx** dialog_ex,
+    DialogEx **dialog_ex,
     int32_t view_id,
-    char* header,
+    char *header,
     uint16_t header_x,
     uint16_t header_y,
-    char* text,
+    char *text,
     uint16_t text_x,
     uint16_t text_y,
-    char* left_button_text,
-    char* right_button_text,
-    char* center_button_text,
-    void (*result_callback)(DialogExResult, void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    char *left_button_text,
+    char *right_button_text,
+    char *center_button_text,
+    void (*result_callback)(DialogExResult, void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a Popup object
@@ -223,18 +223,18 @@ bool easy_flipper_set_dialog_ex(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_popup(
-    Popup** popup,
+    Popup **popup,
     int32_t view_id,
-    char* header,
+    char *header,
     uint16_t header_x,
     uint16_t header_y,
-    char* text,
+    char *text,
     uint16_t text_x,
     uint16_t text_y,
-    void (*result_callback)(void*),
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher,
-    void* context);
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
 
 /**
  * @brief Initialize a Loading object
@@ -245,10 +245,10 @@ bool easy_flipper_set_popup(
  * @return true if successful, false otherwise
  */
 bool easy_flipper_set_loading(
-    Loading** loading,
+    Loading **loading,
     int32_t view_id,
-    uint32_t(previous_callback)(void*),
-    ViewDispatcher** view_dispatcher);
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
 
 /**
  * @brief Set a char butter to a FuriString
@@ -256,6 +256,6 @@ bool easy_flipper_set_loading(
  * @param buffer The buffer to copy the string to
  * @return true if successful, false otherwise
  */
-bool easy_flipper_set_char_to_furi_string(FuriString** furi_string, char* buffer);
+bool easy_flipper_set_char_to_furi_string(FuriString **furi_string, char *buffer);
 
-#endif
+#endif

+ 104 - 86
flip_social/explore/flip_social_explore.c

@@ -1,16 +1,34 @@
 #include "flip_social_explore.h"
 
-FlipSocialModel* flip_social_explore_alloc() {
+FlipSocialModel *flip_social_explore_alloc(void)
+{
+    if (!app_instance)
+    {
+        return NULL;
+    }
+
+    if (!app_instance->submenu_explore)
+    {
+        if (!easy_flipper_set_submenu(&app_instance->submenu_explore, FlipSocialViewLoggedInExploreSubmenu, "Explore", flip_social_callback_to_submenu_logged_in, &app_instance->view_dispatcher))
+        {
+            return NULL;
+        }
+    }
+
     // Allocate memory for each username only if not already allocated
-    FlipSocialModel* explore = malloc(sizeof(FlipSocialModel));
-    if(explore == NULL) {
+    FlipSocialModel *explore = malloc(sizeof(FlipSocialModel));
+    if (explore == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for explore model.");
         return NULL;
     }
-    for(size_t i = 0; i < MAX_EXPLORE_USERS; i++) {
-        if(explore->usernames[i] == NULL) {
+    for (size_t i = 0; i < MAX_EXPLORE_USERS; i++)
+    {
+        if (explore->usernames[i] == NULL)
+        {
             explore->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(explore->usernames[i] == NULL) {
+            if (explore->usernames[i] == NULL)
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
                 return NULL; // Return false on memory allocation failure
             }
@@ -19,30 +37,48 @@ FlipSocialModel* flip_social_explore_alloc() {
     return explore;
 }
 
-void flip_social_free_explore() {
-    if(!flip_social_explore) {
-        FURI_LOG_E(TAG, "Explore model is NULL");
+void flip_social_free_explore(void)
+{
+    if (!app_instance)
+    {
         return;
     }
-    for(int i = 0; i < flip_social_explore->count; i++) {
-        if(flip_social_explore->usernames[i]) {
-            free(flip_social_explore->usernames[i]);
-        }
+    if (app_instance->submenu_explore)
+    {
+        submenu_free(app_instance->submenu_explore);
+        app_instance->submenu_explore = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInExploreSubmenu);
+    }
+    if (!flip_social_explore)
+    {
+        return;
     }
+    free(flip_social_explore);
+    flip_social_explore = NULL;
 }
 
 // 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() {
+bool flip_social_get_explore(void)
+{
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
+    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),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/users.txt");
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/%s.json",
+        keyword);
 
     fhttp.save_received_data = true;
     auth_headers_alloc();
-    if(!flipper_http_get_request_with_headers(
-           "https://www.flipsocial.net/api/user/users/", auth_headers)) {
+    char url[256];
+    snprintf(url, sizeof(url), "https://www.flipsocial.net/api/user/explore/%s/%d/", keyword, MAX_EXPLORE_USERS);
+    if (!flipper_http_get_request_with_headers(url, auth_headers))
+    {
         FURI_LOG_E(TAG, "Failed to send HTTP request for explore");
         fhttp.state = ISSUE;
         return false;
@@ -50,16 +86,46 @@ bool flip_social_get_explore() {
     fhttp.state = RECEIVING;
     return true;
 }
+bool flip_social_get_explore_2(void)
+{
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
+    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),
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/%s.json",
+        keyword);
 
-bool flip_social_parse_json_explore() {
+    fhttp.save_received_data = true;
+    auth_headers_alloc();
+    char url[256];
+    snprintf(url, sizeof(url), "https://www.flipsocial.net/api/user/explore/%s/%d/", keyword, MAX_EXPLORE_USERS);
+    if (!flipper_http_get_request_with_headers(url, auth_headers))
+    {
+        FURI_LOG_E(TAG, "Failed to send HTTP request for explore");
+        fhttp.state = ISSUE;
+        return false;
+    }
+    fhttp.state = RECEIVING;
+    return true;
+}
+
+bool flip_social_parse_json_explore()
+{
     // load the received data from the saved file
-    FuriString* user_data = flipper_http_load_from_file(fhttp.file_path);
-    if(user_data == NULL) {
+    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.");
         return false;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(user_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(user_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(user_data);
         return false;
@@ -67,82 +133,34 @@ bool flip_social_parse_json_explore() {
 
     // Allocate memory for each username only if not already allocated
     flip_social_explore = flip_social_explore_alloc();
-    if(flip_social_explore == NULL) {
+    if (flip_social_explore == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for explore usernames.");
         furi_string_free(user_data);
         free(data_cstr);
         return false;
     }
 
-    // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
-        *pos = ' ';
-    }
-
     // Initialize explore count
     flip_social_explore->count = 0;
 
-    // Extract the users array from the JSON
-    char* json_users = get_json_value("users", data_cstr, MAX_TOKENS);
-    if(json_users == NULL) {
-        FURI_LOG_E(TAG, "Failed to parse users array.");
-        furi_string_free(user_data);
-        free(data_cstr);
-        return false;
-    }
-
-    // Manual tokenization for comma-separated values
-    char* start = json_users + 1; // Skip the opening bracket
-    char* end;
-    while((end = strchr(start, ',')) != NULL && flip_social_explore->count < MAX_EXPLORE_USERS) {
-        *end = '\0'; // Null-terminate the current token
-
-        // Remove quotes
-        if(*start == '"') start++;
-        if(*(end - 1) == '"') *(end - 1) = '\0';
-
-        // Copy username to pre-allocated memory
-        snprintf(
-            flip_social_explore->usernames[flip_social_explore->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
-        flip_social_explore->count++;
-        start = end + 1;
-    }
-
-    // Handle the last token
-    if(*start != '\0' && flip_social_explore->count < MAX_EXPLORE_USERS) {
-        if(*start == '"') start++;
-        if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
-        if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
-
-        snprintf(
-            flip_social_explore->usernames[flip_social_explore->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
-        flip_social_explore->count++;
-    }
-
-    // Add submenu items for the users
+    // set submenu
     submenu_reset(app_instance->submenu_explore);
     submenu_set_header(app_instance->submenu_explore, "Explore");
-    for(int i = 0; i < flip_social_explore->count; i++) {
-        submenu_add_item(
-            app_instance->submenu_explore,
-            flip_social_explore->usernames[i],
-            FlipSocialSubmenuExploreIndexStartIndex + i,
-            flip_social_callback_submenu_choices,
-            app_instance);
+    // Parse the JSON array of usernames
+    for (size_t i = 0; i < MAX_EXPLORE_USERS; i++)
+    {
+        char *username = get_json_array_value("users", i, data_cstr, 64); // currently its 53 tokens (with max explore users at 50)
+        if (username == NULL)
+        {
+            break;
+        }
+        snprintf(flip_social_explore->usernames[i], MAX_USER_LENGTH, "%s", username);
+        submenu_add_item(app_instance->submenu_explore, flip_social_explore->usernames[i], FlipSocialSubmenuExploreIndexStartIndex + i, flip_social_callback_submenu_choices, app_instance);
+        flip_social_explore->count++;
+        free(username);
     }
-
-    // Free the json_users
-    free(json_users);
-    free(start);
-    free(end);
-    furi_string_free(user_data);
     free(data_cstr);
+    furi_string_free(user_data);
     return flip_social_explore->count > 0;
 }

+ 3 - 2
flip_social/explore/flip_social_explore.h

@@ -2,8 +2,9 @@
 #define FLIP_SOCIAL_EXPLORE_H
 #include "flip_social.h"
 #include <callback/flip_social_callback.h>
-FlipSocialModel* flip_social_explore_alloc();
+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
+#endif

+ 214 - 136
flip_social/feed/flip_social_feed.c

@@ -1,120 +1,34 @@
 #include "flip_social_feed.h"
 
-// Set failure FlipSocialFeed object
-bool flip_social_temp_feed() {
-    if(flip_social_feed == NULL) {
-        flip_social_feed = malloc(sizeof(FlipSocialFeed));
-        if(flip_social_feed == NULL) {
-            FURI_LOG_E(TAG, "Failed to allocate memory for feed");
-            return false;
-        }
-    }
-    for(int i = 0; i < 3; i++) {
-        if(flip_social_feed->usernames[i] == NULL) {
-            flip_social_feed->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(flip_social_feed->usernames[i] == NULL) {
-                FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
-                return false;
-            }
-        }
-        if(flip_social_feed->messages[i] == NULL) {
-            flip_social_feed->messages[i] = malloc(MAX_MESSAGE_LENGTH);
-            if(flip_social_feed->messages[i] == NULL) {
-                FURI_LOG_E(TAG, "Failed to allocate memory for message %zu", i);
-                return false;
-            }
-        }
-    }
-    flip_social_feed->usernames[0] = "JBlanked";
-    flip_social_feed->usernames[1] = "FlipperKing";
-    flip_social_feed->usernames[2] = "FlipperQueen";
-    //
-    flip_social_feed->messages[0] =
-        "Welcome. This is a temp message. Either the feed didn't load or there was a server error.";
-    flip_social_feed->messages[1] = "I am the Chosen Flipper.";
-    flip_social_feed->messages[2] = "No one can flip like me.";
-    //
-    flip_social_feed->is_flipped[0] = true;
-    flip_social_feed->is_flipped[1] = false;
-    flip_social_feed->is_flipped[2] = true;
-    //
-    flip_social_feed->ids[0] = 0;
-    flip_social_feed->ids[1] = 1;
-    flip_social_feed->ids[2] = 2;
-    //
-    flip_social_feed->flips[0] = 51;
-    flip_social_feed->flips[1] = 8;
-    flip_social_feed->flips[2] = 23;
-    //
-    flip_social_feed->count = 3;
-    flip_social_feed->index = 0;
-
-    return true;
-}
-
-// Allocate memory for each feed item if not already allocated
-FlipSocialFeed* flip_social_feed_alloc() {
-    // Initialize the feed
-    FlipSocialFeed* feed = (FlipSocialFeed*)malloc(sizeof(FlipSocialFeed));
-    if(!feed) {
-        FURI_LOG_E(TAG, "Failed to allocate memory for feed");
-        return feed;
-    }
-    for(size_t i = 0; i < MAX_FEED_ITEMS; i++) {
-        if(feed->usernames[i] == NULL) {
-            feed->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(feed->usernames[i] == NULL) {
-                FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
-                return NULL;
-            }
-        }
-        if(feed->messages[i] == NULL) {
-            feed->messages[i] = malloc(MAX_MESSAGE_LENGTH);
-            if(feed->messages[i] == NULL) {
-                FURI_LOG_E(TAG, "Failed to allocate memory for message %zu", i);
-                return NULL;
-            }
-        }
-    }
-    return feed;
-}
-
-void flip_social_free_feed() {
-    if(!flip_social_feed) {
-        FURI_LOG_E(TAG, "Feed model is NULL");
-        return;
-    }
-    for(uint32_t i = 0; i < flip_social_feed->count; i++) {
-        if(flip_social_feed->usernames[i]) {
-            free(flip_social_feed->usernames[i]);
-        }
-    }
-}
-
-bool flip_social_get_feed() {
-    if(!app_instance) {
+bool flip_social_get_feed()
+{
+    if (!app_instance)
+    {
         FURI_LOG_E(TAG, "FlipSocialApp is NULL");
         return false;
     }
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
     // Get the feed from the server
-    if(app_instance->login_username_logged_out == NULL) {
+    if (app_instance->login_username_logged_out == NULL)
+    {
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
     snprintf(
         fhttp.file_path,
         sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed.txt");
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed.json");
 
     fhttp.save_received_data = true;
     auth_headers_alloc();
     char command[96];
-    snprintf(
-        command,
-        96,
-        "https://www.flipsocial.net/api/feed/40/%s/extended/",
-        app_instance->login_username_logged_out);
-    if(!flipper_http_get_request_with_headers(command, auth_headers)) {
+    snprintf(command, 96, "https://www.flipsocial.net/api/feed/50/%s/extended/", app_instance->login_username_logged_out);
+    if (!flipper_http_get_request_with_headers(command, auth_headers))
+    {
         FURI_LOG_E(TAG, "Failed to send HTTP request for feed");
         fhttp.state = ISSUE;
         return false;
@@ -123,50 +37,58 @@ bool flip_social_get_feed() {
     return true;
 }
 
-bool flip_social_parse_json_feed() {
+FlipSocialFeedMini *flip_social_parse_json_feed()
+{
     // load the received data from the saved file
-    FuriString* feed_data = flipper_http_load_from_file(fhttp.file_path);
-    if(feed_data == NULL) {
+    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.");
-        return false;
+        return NULL;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(feed_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(feed_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(feed_data);
-        return false;
+        return NULL;
     }
 
-    // Allocate memory for each feed item if not already allocated
-    flip_social_feed = flip_social_feed_alloc();
-    if(flip_social_feed == NULL) {
-        return false;
+    FlipSocialFeedMini *feed_info = (FlipSocialFeedMini *)malloc(sizeof(FlipSocialFeedMini));
+    if (!feed_info)
+    {
+        FURI_LOG_E(TAG, "Failed to allocate memory for feed_info");
+        return NULL;
     }
+
     // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
+    char *pos = data_cstr;
+    while ((pos = strchr(pos, '\n')) != NULL)
+    {
         *pos = ' ';
     }
 
-    // Initialize feed count
-    flip_social_feed->count = 0;
+    int feed_count = 0;
 
     // Iterate through the feed array
-    for(int i = 0; i < MAX_FEED_ITEMS; i++) {
+    for (int i = 0; i < MAX_FEED_ITEMS; i++)
+    {
         // Parse each item in the array
-        char* item = get_json_array_value("feed", i, data_cstr, MAX_TOKENS);
-        if(item == NULL) {
+        char *item = get_json_array_value("feed", i, data_cstr, MAX_TOKENS);
+        if (item == NULL)
+        {
             break;
         }
 
         // Extract individual fields from the JSON object
-        char* username = get_json_value("username", item, MAX_TOKENS);
-        char* message = get_json_value("message", item, MAX_TOKENS);
-        char* flipped = get_json_value("flipped", item, MAX_TOKENS);
-        char* flips = get_json_value("flip_count", item, MAX_TOKENS);
-        char* id = get_json_value("id", item, MAX_TOKENS);
+        char *username = get_json_value("username", item, 40);
+        char *message = get_json_value("message", item, 40);
+        char *flipped = get_json_value("flipped", item, 40);
+        char *flips = get_json_value("flip_count", item, 40);
+        char *id = get_json_value("id", item, 40);
 
-        if(username == NULL || message == NULL || flipped == NULL || id == NULL) {
+        if (username == NULL || message == NULL || flipped == NULL || id == NULL)
+        {
             FURI_LOG_E(TAG, "Failed to parse item fields.");
             free(item);
             free(username);
@@ -177,16 +99,19 @@ bool flip_social_parse_json_feed() {
             continue;
         }
 
-        // Safely copy strings with bounds checking
-        snprintf(flip_social_feed->usernames[i], MAX_USER_LENGTH, "%s", username);
-        snprintf(flip_social_feed->messages[i], MAX_MESSAGE_LENGTH, "%s", message);
-
-        // Store boolean and integer values
-        flip_social_feed->is_flipped[i] = strstr(flipped, "true") != NULL;
-        flip_social_feed->ids[i] = atoi(id);
-        flip_social_feed->flips[i] = atoi(flips);
-
-        flip_social_feed->count++;
+        if (!flip_social_save_post(id, item))
+        {
+            FURI_LOG_E(TAG, "Failed to save post.");
+            free(item);
+            free(username);
+            free(message);
+            free(flipped);
+            free(flips);
+            free(id);
+            continue;
+        }
+        feed_count++;
+        feed_info->ids[i] = atoi(id);
 
         // Free allocated memory
         free(item);
@@ -197,7 +122,160 @@ bool flip_social_parse_json_feed() {
         free(id);
     }
 
+    // Store the number of feed items
+    feed_info->count = feed_count;
+    feed_info->index = 0;
+
+    furi_string_free(feed_data);
+    free(data_cstr);
+    return feed_info;
+}
+
+bool flip_social_load_feed_post(int post_id)
+{
+    char file_path[128];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed_post_%d.json", post_id);
+
+    // load the received data from the saved file
+    FuriString *feed_data = flipper_http_load_from_file(file_path);
+    if (feed_data == NULL)
+    {
+        FURI_LOG_E(TAG, "Failed to load received data from file.");
+        return false;
+    }
+    char *data_cstr = (char *)furi_string_get_cstr(feed_data);
+    if (data_cstr == NULL)
+    {
+        FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
+        furi_string_free(feed_data);
+        return false;
+    }
+
+    // Parse the feed post
+    if (!flip_feed_item)
+    {
+        flip_feed_item = (FlipSocialFeedItem *)malloc(sizeof(FlipSocialFeedItem));
+        if (flip_feed_item == NULL)
+        {
+            FURI_LOG_E(TAG, "Failed to allocate memory for feed post.");
+            furi_string_free(feed_data);
+            free(data_cstr);
+            return false;
+        }
+        flip_feed_item->username = malloc(MAX_USER_LENGTH);
+        flip_feed_item->message = malloc(MAX_MESSAGE_LENGTH);
+    }
+
+    // Extract individual fields from the JSON object
+    char *username = get_json_value("username", data_cstr, 16);
+    char *message = get_json_value("message", data_cstr, 16);
+    char *flipped = get_json_value("flipped", data_cstr, 16);
+    char *flips = get_json_value("flip_count", data_cstr, 16);
+    char *id = get_json_value("id", data_cstr, 16);
+
+    if (username == NULL || message == NULL || flipped == NULL || id == NULL)
+    {
+        FURI_LOG_E(TAG, "Failed to parse item fields.");
+        free(username);
+        free(message);
+        free(flipped);
+        free(flips);
+        free(id);
+        free(data_cstr);
+        furi_string_free(feed_data);
+        return false;
+    }
+
+    // Safely copy strings with bounds checking
+    snprintf(flip_feed_item->username, MAX_USER_LENGTH, "%s", username);
+    snprintf(flip_feed_item->message, MAX_MESSAGE_LENGTH, "%s", message);
+
+    // Store boolean and integer values
+    flip_feed_item->is_flipped = strstr(flipped, "true") != NULL;
+    flip_feed_item->id = atoi(id);
+    flip_feed_item->flips = atoi(flips);
+
+    // Free allocated memory
+    free(username);
+    free(message);
+    free(flipped);
+    free(flips);
+    free(id);
+
     furi_string_free(feed_data);
     free(data_cstr);
-    return flip_social_feed->count > 0;
+
+    return true;
 }
+
+bool flip_social_load_initial_feed()
+{
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
+    if (!easy_flipper_set_loading(&app_instance->loading, FlipSocialViewLoading, flip_social_callback_to_submenu_logged_in, &app_instance->view_dispatcher))
+    {
+        FURI_LOG_E(TAG, "Failed to set loading screen");
+        return false;
+    }
+    view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+    if (flip_social_get_feed()) // start the async request
+    {
+        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;
+        view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+        loading_free(app_instance->loading);
+        return false;
+    }
+    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);
+
+    // load feed info
+    flip_feed_info = flip_social_parse_json_feed();
+    if (!flip_feed_info || flip_feed_info->count < 1)
+    {
+        FURI_LOG_E(TAG, "Failed to parse JSON feed");
+        fhttp.state = ISSUE;
+        view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+        loading_free(app_instance->loading);
+        return false;
+    }
+
+    // load the current feed post
+    if (!flip_social_load_feed_post(flip_feed_info->ids[flip_feed_info->index]))
+    {
+        FURI_LOG_E(TAG, "Failed to load feed post");
+        fhttp.state = ISSUE;
+        view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+        loading_free(app_instance->loading);
+        return false;
+    }
+    if (!feed_dialog_alloc())
+    {
+        FURI_LOG_E(TAG, "Failed to allocate feed dialog");
+        fhttp.state = ISSUE;
+        view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+        loading_free(app_instance->loading);
+        return false;
+    }
+    view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewFeedDialog);
+    view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
+    loading_free(app_instance->loading);
+
+    return true;
+}

+ 4 - 4
flip_social/feed/flip_social_feed.h

@@ -2,10 +2,10 @@
 #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_temp_feed();
-FlipSocialFeed* flip_social_feed_alloc();
-void flip_social_free_feed();
 bool flip_social_get_feed();
-bool flip_social_parse_json_feed();
+bool flip_social_load_feed_post(int post_id);
+bool flip_social_load_initial_feed();
+FlipSocialFeedMini *flip_social_parse_json_feed();
 #endif

+ 204 - 167
flip_social/flip_social.c

@@ -1,14 +1,12 @@
 #include "flip_social.h"
 
-FlipSocialFeed* flip_social_feed = NULL; // Store the feed
-FlipSocialModel* flip_social_friends = NULL; // Store the friends
-FlipSocialModel2* flip_social_message_users =
-    NULL; // Store the users that have sent messages to the logged in user
-FlipSocialModel* flip_social_explore = NULL; // Store the users to explore
-FlipSocialMessage* flip_social_messages =
-    NULL; // Store the messages between the logged in user and the selected user
-
-FlipSocialApp* app_instance = NULL;
+FlipSocialModel *flip_social_friends = NULL;        // Store the friends
+FlipSocialModel2 *flip_social_message_users = NULL; // Store the users that have sent messages to the logged in user
+FlipSocialModel *flip_social_explore = NULL;        // Store the users to explore
+FlipSocialMessage *flip_social_messages = NULL;     // Store the messages between the logged in user and the selected user
+FlipSocialFeedMini *flip_feed_info = NULL;          // Store the feed info
+FlipSocialFeedItem *flip_feed_item = NULL;          // Store a feed item
+FlipSocialApp *app_instance = NULL;
 
 bool flip_social_sent_login_request = false;
 bool flip_social_sent_register_request = false;
@@ -17,265 +15,304 @@ bool flip_social_register_success = false;
 bool flip_social_dialog_shown = false;
 bool flip_social_dialog_stop = false;
 bool flip_social_send_message = false;
-char* last_explore_response = NULL;
-char* selected_message = NULL;
+char *selected_message = NULL;
 
 char auth_headers[256] = {0};
 
+void flip_social_loader_free_model(View *view);
+
 /**
  * @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) {
-    if(!app) {
+void flip_social_app_free(FlipSocialApp *app)
+{
+    if (!app)
+    {
         FURI_LOG_E(TAG, "FlipSocialApp is NULL");
         return;
     }
-    if(!app->view_dispatcher) {
+    if (!app->view_dispatcher)
+    {
         FURI_LOG_E(TAG, "ViewDispatcher is NULL");
         return;
     }
 
     // Free Submenu(s)
-    if(app->submenu_logged_out) {
+    if (app->submenu_logged_out)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
         submenu_free(app->submenu_logged_out);
     }
-    if(app->submenu_logged_in) {
+    if (app->submenu_logged_in)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSubmenu);
         submenu_free(app->submenu_logged_in);
     }
-    if(app->submenu_compose) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInCompose);
-        submenu_free(app->submenu_compose);
-    }
-    if(app->submenu_explore) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInExploreSubmenu);
-        submenu_free(app->submenu_explore);
-    }
-    if(app->submenu_friends) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInFriendsSubmenu);
-        submenu_free(app->submenu_friends);
-    }
-    if(app->submenu_messages) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessagesSubmenu);
-        submenu_free(app->submenu_messages);
-    }
-    if(app->submenu_messages_user_choices) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInMessagesUserChoices);
+    //
+    if (app->submenu_messages_user_choices)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessagesUserChoices);
         submenu_free(app->submenu_messages_user_choices);
     }
 
     // Free Variable Item List(s)
-    if(app->variable_item_list_logged_out_wifi_settings) {
+    if (app->variable_item_list_logged_out_wifi_settings)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutWifiSettings);
         variable_item_list_free(app->variable_item_list_logged_out_wifi_settings);
     }
-    if(app->variable_item_list_logged_out_login) {
+    if (app->variable_item_list_logged_out_login)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutLogin);
         variable_item_list_free(app->variable_item_list_logged_out_login);
     }
-    if(app->variable_item_list_logged_out_register) {
+    if (app->variable_item_list_logged_out_register)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutRegister);
         variable_item_list_free(app->variable_item_list_logged_out_register);
     }
-    if(app->variable_item_list_logged_in_profile) {
+    if (app->variable_item_list_logged_in_profile)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInProfile);
         variable_item_list_free(app->variable_item_list_logged_in_profile);
     }
-    if(app->variable_item_list_logged_in_settings) {
+    if (app->variable_item_list_logged_in_settings)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSettings);
         variable_item_list_free(app->variable_item_list_logged_in_settings);
     }
-    if(app->variable_item_list_logged_in_settings_wifi) {
+    if (app->variable_item_list_logged_in_settings_wifi)
+    {
         view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSettingsWifi);
         variable_item_list_free(app->variable_item_list_logged_in_settings_wifi);
     }
 
     // Free Text Input(s)
-    if(app->text_input_logged_out_wifi_settings_ssid) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutWifiSettingsSSIDInput);
+    if (app->text_input_logged_out_wifi_settings_ssid)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutWifiSettingsSSIDInput);
         text_input_free(app->text_input_logged_out_wifi_settings_ssid);
     }
-    if(app->text_input_logged_out_wifi_settings_password) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutWifiSettingsPasswordInput);
+    if (app->text_input_logged_out_wifi_settings_password)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutWifiSettingsPasswordInput);
         text_input_free(app->text_input_logged_out_wifi_settings_password);
     }
-    if(app->text_input_logged_out_login_username) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutLoginUsernameInput);
+    if (app->text_input_logged_out_login_username)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutLoginUsernameInput);
         text_input_free(app->text_input_logged_out_login_username);
     }
-    if(app->text_input_logged_out_login_password) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutLoginPasswordInput);
+    if (app->text_input_logged_out_login_password)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutLoginPasswordInput);
         text_input_free(app->text_input_logged_out_login_password);
     }
-    if(app->text_input_logged_out_register_username) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutRegisterUsernameInput);
+    if (app->text_input_logged_out_register_username)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutRegisterUsernameInput);
         text_input_free(app->text_input_logged_out_register_username);
     }
-    if(app->text_input_logged_out_register_password) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutRegisterPasswordInput);
+    if (app->text_input_logged_out_register_password)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutRegisterPasswordInput);
         text_input_free(app->text_input_logged_out_register_password);
     }
-    if(app->text_input_logged_out_register_password_2) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedOutRegisterPassword2Input);
+    if (app->text_input_logged_out_register_password_2)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutRegisterPassword2Input);
         text_input_free(app->text_input_logged_out_register_password_2);
     }
-    if(app->text_input_logged_in_change_password) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInChangePasswordInput);
+    if (app->text_input_logged_in_change_password)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInChangePasswordInput);
         text_input_free(app->text_input_logged_in_change_password);
     }
-    if(app->text_input_logged_in_compose_pre_save_input) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInComposeAddPreSaveInput);
+    if (app->text_input_logged_in_change_bio)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInChangeBioInput);
+        text_input_free(app->text_input_logged_in_change_bio);
+    }
+    if (app->text_input_logged_in_compose_pre_save_input)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInComposeAddPreSaveInput);
         text_input_free(app->text_input_logged_in_compose_pre_save_input);
     }
-    if(app->text_input_logged_in_wifi_settings_ssid) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInWifiSettingsSSIDInput);
+    if (app->text_input_logged_in_wifi_settings_ssid)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInWifiSettingsSSIDInput);
         text_input_free(app->text_input_logged_in_wifi_settings_ssid);
     }
-    if(app->text_input_logged_in_wifi_settings_password) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInWifiSettingsPasswordInput);
+    if (app->text_input_logged_in_wifi_settings_password)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInWifiSettingsPasswordInput);
         text_input_free(app->text_input_logged_in_wifi_settings_password);
     }
-    if(app->text_input_logged_in_messages_new_message) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInMessagesNewMessageInput);
+    if (app->text_input_logged_in_messages_new_message)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessagesNewMessageInput);
         text_input_free(app->text_input_logged_in_messages_new_message);
     }
-    if(app->text_input_logged_in_messages_new_message_user_choices) {
-        view_dispatcher_remove_view(
-            app->view_dispatcher, FlipSocialViewLoggedInMessagesNewMessageUserChoicesInput);
+    if (app->text_input_logged_in_messages_new_message_user_choices)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessagesNewMessageUserChoicesInput);
         text_input_free(app->text_input_logged_in_messages_new_message_user_choices);
     }
+    if (app->text_input_logged_in_explore)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInExploreInput);
+        text_input_free(app->text_input_logged_in_explore);
+    }
+    if (app->text_input_logged_in_message_users)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessageUsersInput);
+        text_input_free(app->text_input_logged_in_message_users);
+    }
 
     // Free Widget(s)
-    if(app->widget_logged_out_about) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutAbout);
-        widget_free(app->widget_logged_out_about);
-    }
-    if(app->widget_logged_in_about) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInSettingsAbout);
-        widget_free(app->widget_logged_in_about);
+    if (app->widget_result)
+    {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewWidgetResult);
+        widget_free(app->widget_result);
     }
 
     // Free View(s)
-    if(app->view_process_login) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutProcessLogin);
-        view_free(app->view_process_login);
-    }
-    if(app->view_process_register) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedOutProcessRegister);
-        view_free(app->view_process_register);
-    }
-    if(app->view_process_feed) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInFeed);
-        view_free(app->view_process_feed);
-    }
-    if(app->view_process_compose) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInProcessCompose);
-        view_free(app->view_process_compose);
-    }
-    if(app->view_process_explore) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInExploreProccess);
-        view_free(app->view_process_explore);
-    }
-    if(app->view_process_friends) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInFriendsProcess);
-        view_free(app->view_process_friends);
-    }
-    if(app->view_process_messages) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipSocialViewLoggedInMessagesProcess);
-        view_free(app->view_process_messages);
+    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);
+    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)
+    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)
+    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)
+    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)
+    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)
+    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)
+    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->compose_pre_save_logged_in) free(app->compose_pre_save_logged_in);
-    if(app->compose_pre_save_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->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)
+    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)
+    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(last_explore_response) free(last_explore_response);
-    if(selected_message) free(selected_message);
-
-    if(app->input_event && app->input_event_queue)
-        furi_pubsub_unsubscribe(app->input_event_queue, app->input_event);
+    if (selected_message)
+        free(selected_message);
+    if (app->explore_user_bio)
+        free(app->explore_user_bio);
 
     // DeInit UART
     flipper_http_deinit();
 
     // Free the app structure
-    if(app_instance) free(app_instance);
+    if (app_instance)
+        free(app_instance);
 }
 
-void auth_headers_alloc(void) {
-    if(!app_instance) {
+void auth_headers_alloc(void)
+{
+    if (!app_instance)
+    {
+        snprintf(auth_headers, sizeof(auth_headers), "{\"Content-Type\":\"application/json\"}");
         return;
     }
 
-    if(app_instance->login_username_logged_out && app_instance->login_password_logged_out) {
-        snprintf(
-            auth_headers,
-            sizeof(auth_headers),
-            "{\"Content-Type\":\"application/json\",\"username\":\"%s\",\"password\":\"%s\"}",
-            app_instance->login_username_logged_out,
-            app_instance->login_password_logged_out);
-    } else if(app_instance->login_username_logged_in && app_instance->change_password_logged_in) {
-        snprintf(
-            auth_headers,
-            sizeof(auth_headers),
-            "{\"Content-Type\":\"application/json\",\"username\":\"%s\",\"password\":\"%s\"}",
-            app_instance->login_username_logged_in,
-            app_instance->change_password_logged_in);
-    } else {
+    if (app_instance->login_username_logged_out && app_instance->login_password_logged_out && strlen(app_instance->login_username_logged_out) > 0 && strlen(app_instance->login_password_logged_out) > 0)
+    {
+        snprintf(auth_headers, sizeof(auth_headers), "{\"Content-Type\":\"application/json\",\"username\":\"%s\",\"password\":\"%s\"}", app_instance->login_username_logged_out, app_instance->login_password_logged_out);
+    }
+    else if (app_instance->login_username_logged_in && app_instance->change_password_logged_in && strlen(app_instance->login_username_logged_in) > 0 && strlen(app_instance->change_password_logged_in) > 0)
+    {
+        snprintf(auth_headers, sizeof(auth_headers), "{\"Content-Type\":\"application/json\",\"username\":\"%s\",\"password\":\"%s\"}", app_instance->login_username_logged_in, app_instance->change_password_logged_in);
+    }
+    else
+    {
         snprintf(auth_headers, sizeof(auth_headers), "{\"Content-Type\":\"application/json\"}");
     }
 }
+
+FlipSocialFeedMini *flip_feed_info_alloc(void)
+{
+    FlipSocialFeedMini *feed_info = (FlipSocialFeedMini *)malloc(sizeof(FlipSocialFeedMini));
+    if (!feed_info)
+    {
+        FURI_LOG_E(TAG, "Failed to allocate memory for feed_info");
+        return NULL;
+    }
+    feed_info->count = 0;
+    feed_info->index = 0;
+    return feed_info;
+}
+
+void flip_feed_info_free(void)
+{
+    if (!flip_feed_info)
+    {
+        return;
+    }
+    free(flip_feed_info);
+    flip_feed_info = NULL;
+}

+ 223 - 219
flip_social/flip_social.h

@@ -9,312 +9,315 @@
 #include <flip_social_icons.h>
 #define TAG "FlipSocial"
 
-#define MAX_PRE_SAVED_MESSAGES 25 // 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_TOKENS             450 // Adjust based on expected JSON tokens
-#define MAX_FEED_ITEMS         41 // Maximum number of feed items
-#define MAX_LINE_LENGTH        30
-#define MAX_MESSAGE_USERS      20 // Maximum number of users to display in the submenu
-#define MAX_MESSAGES           20 // Maximum number of meesages between each user
+#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_TOKENS 576            // Adjust based on expected JSON tokens
+#define MAX_FEED_ITEMS 50         // Maximum number of feed items
+#define MAX_LINE_LENGTH 30
+#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
 
 #define SETTINGS_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/settings.bin"
-#define PRE_SAVED_MESSAGES_PATH \
-    STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/pre_saved_messages.txt"
+#define PRE_SAVED_MESSAGES_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/pre_saved_messages.txt"
 
 // Define the submenu items for our Hello World application
-typedef enum {
-    FlipSocialSubmenuLoggedOutIndexLogin, // click to go to the login screen
-    FlipSocialSubmenuLoggedOutIndexRegister, // click to go to the register screen
-    FlipSocialSubmenuLoggedOutIndexAbout, // click to go to the about screen
+typedef enum
+{
+    FlipSocialSubmenuLoggedOutIndexLogin,        // click to go to the login screen
+    FlipSocialSubmenuLoggedOutIndexRegister,     // click to go to the register screen
+    FlipSocialSubmenuLoggedOutIndexAbout,        // click to go to the about screen
     FlipSocialSubmenuLoggedOutIndexWifiSettings, // click to go to the wifi settings screen
     //
-    FlipSocialSubmenuLoggedInIndexProfile, // click to go to the profile screen
-    FlipSocialSubmenuExploreIndex, // click to go to the explore
-    FlipSocialSubmenuLoggedInIndexFeed, // click to go to the feed screen
+    FlipSocialSubmenuLoggedInIndexProfile,  // click to go to the profile screen
+    FlipSocialSubmenuExploreIndex,          // click to go to the explore
+    FlipSocialSubmenuLoggedInIndexFeed,     // click to go to the feed screen
     FlipSocialSubmenuLoggedInIndexMessages, // click to go to the messages screen
-    FlipSocialSubmenuLoggedInIndexCompose, // click to go to the compose screen
+    FlipSocialSubmenuLoggedInIndexCompose,  // click to go to the compose screen
     FlipSocialSubmenuLoggedInIndexSettings, // click to go to the settings screen
     FlipSocialSubmenuLoggedInSignOutButton, // click to sign out
     //
     FlipSocialSubmenuLoggedInIndexMessagesNewMessage, // click to add a new message
     //
-    FlipSocialSubmenuComposeIndexAddPreSave, // click to add a pre-saved message
-    FlipSocialSubemnuComposeIndexStartIndex =
-        100, // starting index for the first pre saved message
+    FlipSocialSubmenuComposeIndexAddPreSave,       // click to add a pre-saved message
+    FlipSocialSubemnuComposeIndexStartIndex = 100, // starting index for the first pre saved message
     //
-    FlipSocialSubmenuExploreIndexStartIndex = 150, // starting index for the users to explore
+    FlipSocialSubmenuExploreIndexStartIndex = 200, // starting index for the users to explore
     //
-    FlipSocialSubmenuLoggedInIndexFriendsStart = 200, // starting index for the friends
+    FlipSocialSubmenuLoggedInIndexFriendsStart = 400, // starting index for the friends
     //
-    FlipSocialSubmenuLoggedInIndexMessagesUsersStart = 250, // starting index for the messages
+    FlipSocialSubmenuLoggedInIndexMessagesUsersStart = 600, // starting index for the messages
     //
-    FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart =
-        300, // click to select a user to message
+    FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart = 800, // click to select a user to message
 } FlipSocialSubmenuIndex;
 
 // Define the ScriptPlaylist structure
-typedef struct {
-    char* messages[MAX_PRE_SAVED_MESSAGES];
+typedef struct
+{
+    char *messages[MAX_PRE_SAVED_MESSAGES];
     size_t count;
     size_t index;
 } PreSavedPlaylist;
 
-typedef struct {
-    char* usernames[MAX_FEED_ITEMS];
-    char* messages[MAX_FEED_ITEMS];
-    bool is_flipped[MAX_FEED_ITEMS];
+// Define a FlipSocialFeed individual item
+typedef struct
+{
+    char *username;
+    char *message;
+    bool is_flipped;
+    int id;
+    int flips;
+} FlipSocialFeedItem;
+
+typedef struct
+{
     int ids[MAX_FEED_ITEMS];
-    int flips[MAX_FEED_ITEMS];
     size_t count;
     size_t index;
-} FlipSocialFeed;
+} FlipSocialFeedMini;
 
-typedef struct {
-    char* usernames[MAX_EXPLORE_USERS];
+typedef struct
+{
+    char *usernames[MAX_EXPLORE_USERS];
     int count;
     int index;
 } FlipSocialModel;
 
-typedef struct {
-    char* usernames[MAX_MESSAGE_USERS];
+typedef struct
+{
+    char *usernames[MAX_MESSAGE_USERS];
     int count;
     int index;
 } FlipSocialModel2;
 
-typedef struct {
-    char* usernames[MAX_MESSAGES];
-    char* messages[MAX_MESSAGES];
+typedef struct
+{
+    char *usernames[MAX_MESSAGES];
+    char *messages[MAX_MESSAGES];
     int count;
     int index;
 } FlipSocialMessage;
 
 // Define views for our Hello World application
-typedef enum {
-    FlipSocialViewLoggedOutSubmenu, // The menu if the user is not logged in
-    FlipSocialViewLoggedOutLogin, // The login screen
-    FlipSocialViewLoggedOutRegister, // The register screen
-    FlipSocialViewLoggedOutAbout, // The about screen
+typedef enum
+{
+    FlipSocialViewLoggedOutSubmenu,      // The menu if the user is not logged in
+    FlipSocialViewLoggedOutLogin,        // The login screen
+    FlipSocialViewLoggedOutRegister,     // The register screen
+    FlipSocialViewLoggedOutAbout,        // The about screen
     FlipSocialViewLoggedOutWifiSettings, // The wifi settings screen
     //
-    FlipSocialViewLoggedOutLoginUsernameInput, // Text input screen for username input on login screen
-    FlipSocialViewLoggedOutLoginPasswordInput, // Text input screen for password input on login screen
-    FlipSocialViewLoggedOutRegisterUsernameInput, // Text input screen for username input on register screen
-    FlipSocialViewLoggedOutRegisterPasswordInput, // Text input screen for password input on register screen
-    FlipSocialViewLoggedOutRegisterPassword2Input, // Text input screen for password 2 input on register screen
-    FlipSocialViewLoggedOutWifiSettingsSSIDInput, // Text input screen for SSID input on wifi screen
+    FlipSocialViewLoggedOutLoginUsernameInput,        // Text input screen for username input on login screen
+    FlipSocialViewLoggedOutLoginPasswordInput,        // Text input screen for password input on login screen
+    FlipSocialViewLoggedOutRegisterUsernameInput,     // Text input screen for username input on register screen
+    FlipSocialViewLoggedOutRegisterPasswordInput,     // Text input screen for password input on register screen
+    FlipSocialViewLoggedOutRegisterPassword2Input,    // Text input screen for password 2 input on register screen
+    FlipSocialViewLoggedOutWifiSettingsSSIDInput,     // Text input screen for SSID input on wifi screen
     FlipSocialViewLoggedOutWifiSettingsPasswordInput, // Text input screen for Password input on wifi screen
-    FlipSocialViewLoggedOutProcessLogin, // The screen displayed after clicking login
-    FlipSocialViewLoggedOutProcessRegister, // The screen displayed after clicking register
+    FlipSocialViewLoggedOutProcessLogin,              // The screen displayed after clicking login
+    FlipSocialViewLoggedOutProcessRegister,           // The screen displayed after clicking register
     //
-    FlipSocialViewLoggedInSubmenu, // The menu if the user is logged in
-    FlipSocialViewLoggedInProfile, // The profile screen
-    FlipSocialViewLoggedInFeed, // The feed screen
-    FlipSocialViewLoggedInCompose, // The compose screen
+    FlipSocialViewLoggedInSubmenu,  // The menu if the user is logged in
+    FlipSocialViewLoggedInProfile,  // The profile screen
+    FlipSocialViewLoggedInFeed,     // The feed screen
+    FlipSocialViewLoggedInCompose,  // The compose screen
     FlipSocialViewLoggedInSettings, // The settings screen
     //
-    FlipSocialViewLoggedInChangePasswordInput, // Text input screen for password input on change password screen
+    FlipSocialViewLoggedInChangeBioInput,         // Text input screen for bio input on profile screen
+    FlipSocialViewLoggedInChangePasswordInput,    // Text input screen for password input on change password screen
     FlipSocialViewLoggedInComposeAddPreSaveInput, // Text input screen for add text input on compose screen
     //
-    FlipSocialViewLoggedInMessagesNewMessageInput, // Text input screen for new message input on messages screen
+    FlipSocialViewLoggedInMessagesNewMessageInput,            // Text input screen for new message input on messages screen
     FlipSocialViewLoggedInMessagesNewMessageUserChoicesInput, // Text input screen for new message input on messages screen
-    FlipSocialViewLoggedInMessagesUserChoices, // the view after clicking [New Message] - select a user to message, then direct to input view
+    FlipSocialViewLoggedInMessagesUserChoices,                // the view after clicking [New Message] - select a user to message, then direct to input view
+    FlipSocialViewLoggedInExploreInput,                       // Text input screen for explore input on explore screen
+    FlipSocialViewLoggedInMessageUsersInput,
     //
-    FlipSocialViewLoggedInSettingsAbout, // The about screen
-    FlipSocialViewLoggedInSettingsWifi, // The wifi settings screen
-    FlipSocialViewLoggedInWifiSettingsSSIDInput, // Text input screen for SSID input on wifi screen
+    FlipSocialViewLoggedInSettingsAbout,             // The about screen
+    FlipSocialViewLoggedInSettingsWifi,              // The wifi settings screen
+    FlipSocialViewLoggedInWifiSettingsSSIDInput,     // Text input screen for SSID input on wifi screen
     FlipSocialViewLoggedInWifiSettingsPasswordInput, // Text input screen for Password input on wifi screen
-    FlipSocialViewLoggedInProcessCompose, // The dialog view to delete or send the clicked pre-saved text
     //
     FlipSocialViewLoggedInSignOut, // The view after clicking the sign out button
     //
-    FlipSocialViewLoggedInExploreSubmenu, // The view after clicking the explore button
-    FlipSocialViewLoggedInExploreProccess, // The view after clicking on a user in the explore screen
-    FlipSocialViewLoggedInFriendsSubmenu, // The view after clicking the friends button on the profile screen
-    FlipSocialViewLoggedInFriendsProcess, // The view after clicking on a friend in the friends screen
+    FlipSocialViewLoggedInExploreSubmenu,  // The view after clicking the explore button
+    FlipSocialViewLoggedInFriendsSubmenu,  // The view after clicking the friends button on the profile screen
     FlipSocialViewLoggedInMessagesSubmenu, // The view after clicking the messages button on the profile screen
-    FlipSocialViewLoggedInMessagesProcess, // The view after clicking on a user in the messages screen
+    //
+    FlipSocialViewLoading, // The loading screen
+    //
+    FlipSocialViewWidgetResult, // The text box that displays the random fact
+    FlipSocialViewLoader,       // The loader screen retrieves data from the internet
+    //
+    FlipSocialViewExploreDialog,  // The dialog for the explore screen
+    FlipSocialViewFriendsDialog,  // The dialog for the friends screen
+    FlipSocialViewMessagesDialog, // The dialog for the messages screen
+    FlipSocialViewComposeDialog,  // The dialog for the compose screen
+    FlipSocialViewFeedDialog,     // The dialog for the feed screen
 } FlipSocialView;
 
 // Define the application structure
-typedef struct {
-    ViewDispatcher* view_dispatcher; // Switches between our views
-    Submenu* submenu_logged_out; // The application submenu (logged out)
-    Submenu* submenu_logged_in; // The application submenu (logged in)
-    Submenu* submenu_compose; // The application submenu (compose)
-    Submenu* submenu_explore; // The application submenu (explore)
-    Submenu* submenu_friends; // The application submenu (friends)
-    Submenu* submenu_messages; // The application submenu (messages)
-    Submenu* submenu_messages_user_choices; // The application submenu (messages user choices)
-    Widget* widget_logged_out_about; // The about screen (logged out)
-    Widget* widget_logged_in_about; // The about screen (logged in)
-
-    View* view_process_login; // The screen displayed after clicking login
-    View* view_process_register; // The screen displayed after clicking register
-    View* view_process_feed; // Dialog for the feed screen
-    View* view_process_compose; // Dialog for the compose screen (delete or send)
-    View* view_process_explore; // Dialog for the explore screen (view user profile - add or delete friend)
-    View* view_process_friends; // Dialog for the friends screen (view user profile - add or delete friend)
-    View* view_process_messages; // Dialog for the messages screen (next, previous, send message)
-
-    VariableItemList* variable_item_list_logged_out_wifi_settings; // The wifi settings menu
-    VariableItemList* variable_item_list_logged_out_login; // The login menu
-    VariableItemList* variable_item_list_logged_out_register; // The register menu
+typedef struct
+{
+    View *view_loader;
+    Widget *widget_result;
     //
-    VariableItemList* variable_item_list_logged_in_profile; // The profile menu
-    VariableItemList* variable_item_list_logged_in_settings; // The settings menu
-    VariableItemList* variable_item_list_logged_in_settings_wifi; // The wifi settings menu
-
-    TextInput*
-        text_input_logged_out_wifi_settings_ssid; // Text input for ssid input on wifi settings screen
-    TextInput*
-        text_input_logged_out_wifi_settings_password; // Text input for password input on wifi settings screen
-    TextInput* text_input_logged_out_login_username; // Text input for username input on login screen
-    TextInput* text_input_logged_out_login_password; // Text input for password input on login screen
-    TextInput*
-        text_input_logged_out_register_username; // Text input for username input on register screen
-    TextInput*
-        text_input_logged_out_register_password; // Text input for password input on register screen
-    TextInput*
-        text_input_logged_out_register_password_2; // Text input for password 2 input on register screen
+    ViewDispatcher *view_dispatcher;        // Switches between our views
+    Submenu *submenu_logged_out;            // The application submenu (logged out)
+    Submenu *submenu_logged_in;             // The application submenu (logged in)
+    Submenu *submenu_compose;               // The application submenu (compose)
+    Submenu *submenu_explore;               // The application submenu (explore)
+    Submenu *submenu_friends;               // The application submenu (friends)
+    Submenu *submenu_messages;              // The application submenu (messages)
+    Submenu *submenu_messages_user_choices; // The application submenu (messages user choices)
+    Widget *widget_logged_out_about;        // The about screen (logged out)
+    Widget *widget_logged_in_about;         // The about screen (logged in)
+
+    VariableItemList *variable_item_list_logged_out_wifi_settings; // The wifi settings menu
+    VariableItemList *variable_item_list_logged_out_login;         // The login menu
+    VariableItemList *variable_item_list_logged_out_register;      // The register menu
     //
-    TextInput*
-        text_input_logged_in_change_password; // Text input for password input on change password screen
-    TextInput*
-        text_input_logged_in_compose_pre_save_input; // Text input for pre save input on compose screen
-    TextInput*
-        text_input_logged_in_wifi_settings_ssid; // Text input for ssid input on wifi settings screen
-    TextInput*
-        text_input_logged_in_wifi_settings_password; // Text input for password input on wifi settings screen
+    VariableItemList *variable_item_list_logged_in_profile;       // The profile menu
+    VariableItemList *variable_item_list_logged_in_settings;      // The settings menu
+    VariableItemList *variable_item_list_logged_in_settings_wifi; // The wifi settings menu
+
+    TextInput *text_input_logged_out_wifi_settings_ssid;     // Text input for ssid input on wifi settings screen
+    TextInput *text_input_logged_out_wifi_settings_password; // Text input for password input on wifi settings screen
+    TextInput *text_input_logged_out_login_username;         // Text input for username input on login screen
+    TextInput *text_input_logged_out_login_password;         // Text input for password input on login screen
+    TextInput *text_input_logged_out_register_username;      // Text input for username input on register screen
+    TextInput *text_input_logged_out_register_password;      // Text input for password input on register screen
+    TextInput *text_input_logged_out_register_password_2;    // Text input for password 2 input on register screen
     //
-    TextInput*
-        text_input_logged_in_messages_new_message; // Text input for new message input on messages screen
-    TextInput* text_input_logged_in_messages_new_message_user_choices; //
-
-    VariableItem*
-        variable_item_logged_out_wifi_settings_ssid; // Reference to the ssid configuration item
-    VariableItem*
-        variable_item_logged_out_wifi_settings_password; // Reference to the password configuration item
-    VariableItem*
-        variable_item_logged_out_login_username; // Reference to the username configuration item
-    VariableItem*
-        variable_item_logged_out_login_password; // Reference to the password configuration item
-    VariableItem*
-        variable_item_logged_out_login_button; // Reference to the login button configuration item
-    VariableItem*
-        variable_item_logged_out_register_username; // Reference to the username configuration item
-    VariableItem*
-        variable_item_logged_out_register_password; // Reference to the password configuration item
-    VariableItem*
-        variable_item_logged_out_register_password_2; // Reference to the password 2 configuration item
-    VariableItem*
-        variable_item_logged_out_register_button; // Reference to the register button configuration item
+    TextInput *text_input_logged_in_change_password;        // Text input for password input on change password screen
+    TextInput *text_input_logged_in_change_bio;             // Text input for bio input on profile screen
+    TextInput *text_input_logged_in_compose_pre_save_input; // Text input for pre save input on compose screen
+    TextInput *text_input_logged_in_wifi_settings_ssid;     // Text input for ssid input on wifi settings screen
+    TextInput *text_input_logged_in_wifi_settings_password; // Text input for password input on wifi settings screen
     //
-    VariableItem*
-        variable_item_logged_in_profile_username; // Reference to the username configuration item
-    VariableItem*
-        variable_item_logged_in_profile_change_password; // Reference to the change password configuration item
-    VariableItem*
-        variable_item_logged_in_settings_about; // Reference to the about configuration item
-    VariableItem*
-        variable_item_logged_in_settings_wifi; // Reference to the wifi settings configuration item
-    VariableItem*
-        variable_item_logged_in_wifi_settings_ssid; // Reference to the ssid configuration item
-    VariableItem*
-        variable_item_logged_in_wifi_settings_password; // Reference to the password configuration item
+    TextInput *text_input_logged_in_messages_new_message;              // Text input for new message input on messages screen
+    TextInput *text_input_logged_in_messages_new_message_user_choices; //
     //
-    VariableItem*
-        variable_item_logged_in_profile_friends; // Reference to the friends configuration item
+    TextInput *text_input_logged_in_explore; // Text input for explore input on explore screen
+    TextInput *text_input_logged_in_message_users;
+
+    VariableItem *variable_item_logged_out_wifi_settings_ssid;     // Reference to the ssid configuration item
+    VariableItem *variable_item_logged_out_wifi_settings_password; // Reference to the password configuration item
+    VariableItem *variable_item_logged_out_login_username;         // Reference to the username configuration item
+    VariableItem *variable_item_logged_out_login_password;         // Reference to the password configuration item
+    VariableItem *variable_item_logged_out_login_button;           // Reference to the login button configuration item
+    VariableItem *variable_item_logged_out_register_username;      // Reference to the username configuration item
+    VariableItem *variable_item_logged_out_register_password;      // Reference to the password configuration item
+    VariableItem *variable_item_logged_out_register_password_2;    // Reference to the password 2 configuration item
+    VariableItem *variable_item_logged_out_register_button;        // Reference to the register button configuration item
+    //
+    VariableItem *variable_item_logged_in_profile_username;        // Reference to the username configuration item
+    VariableItem *variable_item_logged_in_profile_change_password; // Reference to the change password configuration item
+    VariableItem *variable_item_logged_in_profile_change_bio;      // Reference to the change bio configuration item
+    //
+    VariableItem *variable_item_logged_in_settings_about;         // Reference to the about configuration item
+    VariableItem *variable_item_logged_in_settings_wifi;          // Reference to the wifi settings configuration item
+    VariableItem *variable_item_logged_in_wifi_settings_ssid;     // Reference to the ssid configuration item
+    VariableItem *variable_item_logged_in_wifi_settings_password; // Reference to the password configuration item
+    //
+    VariableItem *variable_item_logged_in_profile_friends; // Reference to the friends configuration item
     //
-    FuriPubSub* input_event_queue;
-    FuriPubSubSubscription* input_event;
-
     PreSavedPlaylist pre_saved_messages; // Pre-saved messages for the feed screen
 
-    char* is_logged_in; // Store the login status
+    char *is_logged_in;         // Store the login status
     uint32_t is_logged_in_size; // Size of the login status buffer
 
-    char* login_username_logged_in; // Store the entered login username
-    char* login_username_logged_in_temp_buffer; // Temporary buffer for login username text input
-    uint32_t
-        login_username_logged_in_temp_buffer_size; // Size of the login username temporary buffer
+    char *login_username_logged_in;                     // Store the entered login username
+    char *login_username_logged_in_temp_buffer;         // Temporary buffer for login username text input
+    uint32_t login_username_logged_in_temp_buffer_size; // Size of the login username temporary buffer
 
-    char* wifi_ssid_logged_out; // Store the entered wifi ssid
-    char* wifi_ssid_logged_out_temp_buffer; // Temporary buffer for wifi ssid text input
+    char *change_bio_logged_in;                     // Store the entered bio
+    char *change_bio_logged_in_temp_buffer;         // Temporary buffer for bio text input
+    uint32_t change_bio_logged_in_temp_buffer_size; // Size of the bio temporary buffer
+    //
+    char *wifi_ssid_logged_out;                     // Store the entered wifi ssid
+    char *wifi_ssid_logged_out_temp_buffer;         // Temporary buffer for wifi ssid text input
     uint32_t wifi_ssid_logged_out_temp_buffer_size; // Size of the wifi ssid temporary buffer
 
-    char* wifi_password_logged_out; // Store the entered wifi password
-    char* wifi_password_logged_out_temp_buffer; // Temporary buffer for wifi_password text input
+    char *wifi_password_logged_out;                     // Store the entered wifi password
+    char *wifi_password_logged_out_temp_buffer;         // Temporary buffer for wifi_password text input
     uint32_t wifi_password_logged_out_temp_buffer_size; // Size of the wifi_password temporary buffer
 
-    char* login_username_logged_out; // Store the entered login username
-    char* login_username_logged_out_temp_buffer; // Temporary buffer for login username text input
-    uint32_t
-        login_username_logged_out_temp_buffer_size; // Size of the login username temporary buffer
+    char *login_username_logged_out;                     // Store the entered login username
+    char *login_username_logged_out_temp_buffer;         // Temporary buffer for login username text input
+    uint32_t login_username_logged_out_temp_buffer_size; // Size of the login username temporary buffer
 
-    char* login_password_logged_out; // Store the entered login password
-    char* login_password_logged_out_temp_buffer; // Temporary buffer for login password text input
-    uint32_t
-        login_password_logged_out_temp_buffer_size; // Size of the login password temporary buffer
+    char *login_password_logged_out;                     // Store the entered login password
+    char *login_password_logged_out_temp_buffer;         // Temporary buffer for login password text input
+    uint32_t login_password_logged_out_temp_buffer_size; // Size of the login password temporary buffer
 
-    char* register_username_logged_out; // Store the entered register username
-    char* register_username_logged_out_temp_buffer; // Temporary buffer for register username text input
-    uint32_t
-        register_username_logged_out_temp_buffer_size; // Size of the register username temporary buffer
+    char *register_username_logged_out;                     // Store the entered register username
+    char *register_username_logged_out_temp_buffer;         // Temporary buffer for register username text input
+    uint32_t register_username_logged_out_temp_buffer_size; // Size of the register username temporary buffer
 
-    char* register_password_logged_out; // Store the entered register password
-    char* register_password_logged_out_temp_buffer; // Temporary buffer for register password text input
-    uint32_t
-        register_password_logged_out_temp_buffer_size; // Size of the register password temporary buffer
+    char *register_password_logged_out;                     // Store the entered register password
+    char *register_password_logged_out_temp_buffer;         // Temporary buffer for register password text input
+    uint32_t register_password_logged_out_temp_buffer_size; // Size of the register password temporary buffer
 
-    char* register_password_2_logged_out; // Store the entered register password 2
-    char* register_password_2_logged_out_temp_buffer; // Temporary buffer for register password 2 text input
-    uint32_t
-        register_password_2_logged_out_temp_buffer_size; // Size of the register password 2 temporary buffer
+    char *register_password_2_logged_out;                     // Store the entered register password 2
+    char *register_password_2_logged_out_temp_buffer;         // Temporary buffer for register password 2 text input
+    uint32_t register_password_2_logged_out_temp_buffer_size; // Size of the register password 2 temporary buffer
 
     //
-    char* change_password_logged_in; // Store the entered change password
-    char* change_password_logged_in_temp_buffer; // Temporary buffer for change password text input
-    uint32_t
-        change_password_logged_in_temp_buffer_size; // Size of the change password temporary buffer
+    char *change_password_logged_in;                     // Store the entered change password
+    char *change_password_logged_in_temp_buffer;         // Temporary buffer for change password text input
+    uint32_t change_password_logged_in_temp_buffer_size; // Size of the change password temporary buffer
 
-    char* compose_pre_save_logged_in; // Store the entered add text
-    char* compose_pre_save_logged_in_temp_buffer; // Temporary buffer for add text text input
+    char *compose_pre_save_logged_in;                     // Store the entered add text
+    char *compose_pre_save_logged_in_temp_buffer;         // Temporary buffer for add text text input
     uint32_t compose_pre_save_logged_in_temp_buffer_size; // Size of the add text temporary buffer
 
-    char* wifi_ssid_logged_in; // Store the entered wifi ssid
-    char* wifi_ssid_logged_in_temp_buffer; // Temporary buffer for wifi ssid text input
+    char *wifi_ssid_logged_in;                     // Store the entered wifi ssid
+    char *wifi_ssid_logged_in_temp_buffer;         // Temporary buffer for wifi ssid text input
     uint32_t wifi_ssid_logged_in_temp_buffer_size; // Size of the wifi ssid temporary buffer
 
-    char* wifi_password_logged_in; // Store the entered wifi password
-    char* wifi_password_logged_in_temp_buffer; // Temporary buffer for wifi_password text input
+    char *wifi_password_logged_in;                     // Store the entered wifi password
+    char *wifi_password_logged_in_temp_buffer;         // Temporary buffer for wifi_password text input
     uint32_t wifi_password_logged_in_temp_buffer_size; // Size of the wifi_password temporary buffer
 
     //
-    char* messages_new_message_logged_in; // Store the entered new message
-    char* messages_new_message_logged_in_temp_buffer; // Temporary buffer for new message text input
-    uint32_t
-        messages_new_message_logged_in_temp_buffer_size; // Size of the new message temporary buffer
-
-    char* message_user_choice_logged_in; // Store the entered message to send to the selected user
-    char* message_user_choice_logged_in_temp_buffer; // Temporary buffer for message to send to the selected user
-    uint32_t
-        message_user_choice_logged_in_temp_buffer_size; // Size of the message to send to the selected user temporary buffer
-} FlipSocialApp;
+    char *messages_new_message_logged_in;                     // Store the entered new message
+    char *messages_new_message_logged_in_temp_buffer;         // Temporary buffer for new message text input
+    uint32_t messages_new_message_logged_in_temp_buffer_size; // Size of the new message temporary buffer
 
-void flip_social_app_free(FlipSocialApp* app);
+    char *message_user_choice_logged_in;                     // Store the entered message to send to the selected user
+    char *message_user_choice_logged_in_temp_buffer;         // Temporary buffer for message to send to the selected user
+    uint32_t message_user_choice_logged_in_temp_buffer_size; // Size of the message to send to the selected user temporary buffer
+    //
+    char *explore_logged_in;                     // Store the entered explore
+    char *explore_logged_in_temp_buffer;         // Temporary buffer for explore text input
+    uint32_t explore_logged_in_temp_buffer_size; // Size of the explore temporary buffer
+
+    char *message_users_logged_in;                     // Store the entered message users
+    char *message_users_logged_in_temp_buffer;         // Temporary buffer for message users text input
+    uint32_t message_users_logged_in_temp_buffer_size; // Size of the message users temporary buffer
+
+    Loading *loading; // The loading screen
+    DialogEx *dialog_explore;
+    DialogEx *dialog_friends;
+    DialogEx *dialog_messages;
+    DialogEx *dialog_compose;
+    DialogEx *dialog_feed;
+
+    char *explore_user_bio; // Store the bio of the selected user
+} FlipSocialApp;
 
-extern FlipSocialFeed* flip_social_feed; // Store the feed
-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
-extern FlipSocialModel* flip_social_explore; // Store the users to explore
-extern FlipSocialMessage*
-    flip_social_messages; // Store the messages between the logged in user and the selected user
+void flip_social_app_free(FlipSocialApp *app);
 
-extern FlipSocialApp* app_instance;
+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
+extern FlipSocialModel *flip_social_explore;        // Store the users to explore
+extern FlipSocialMessage *flip_social_messages;     // Store the messages between the logged in user and the selected user
+extern FlipSocialFeedMini *flip_feed_info;          // Store the feed info
+extern FlipSocialFeedItem *flip_feed_item;          // Store a feed item
+extern FlipSocialApp *app_instance;
 
 extern bool flip_social_sent_login_request;
 extern bool flip_social_sent_register_request;
@@ -323,9 +326,10 @@ extern bool flip_social_register_success;
 extern bool flip_social_dialog_shown;
 extern bool flip_social_dialog_stop;
 extern bool flip_social_send_message;
-extern char* last_explore_response;
-extern char* selected_message;
+extern char *selected_message;
 extern char auth_headers[256];
 
 void auth_headers_alloc(void);
-#endif
+FlipSocialFeedMini *flip_feed_info_alloc(void);
+void flip_feed_info_free(void);
+#endif

+ 195 - 113
flip_social/flip_storage/flip_social_storage.c

@@ -1,23 +1,25 @@
 #include "flip_social_storage.h"
 
 // Function to save the playlist
-void save_playlist(const PreSavedPlaylist* playlist) {
-    if(!playlist) {
+void save_playlist(const PreSavedPlaylist *playlist)
+{
+    if (!playlist)
+    {
         FURI_LOG_E(TAG, "Playlist is NULL");
         return;
     }
     // Create the directory for saving settings
     char directory_path[128];
-    snprintf(
-        directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social");
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social");
 
     // Create the directory
-    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Storage *storage = furi_record_open(RECORD_STORAGE);
     storage_common_mkdir(storage, directory_path);
 
     // Open the settings file
-    File* file = storage_file_alloc(storage);
-    if(!storage_file_open(file, PRE_SAVED_MESSAGES_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
+    File *file = storage_file_alloc(storage);
+    if (!storage_file_open(file, PRE_SAVED_MESSAGES_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
         FURI_LOG_E(TAG, "Failed to open settings file for writing: %s", PRE_SAVED_MESSAGES_PATH);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
@@ -25,15 +27,17 @@ void save_playlist(const PreSavedPlaylist* playlist) {
     }
 
     // Write each playlist message on a separate line
-    for(size_t i = 0; i < playlist->count; ++i) {
+    for (size_t i = 0; i < playlist->count; ++i)
+    {
         // Add a newline character after each message
-        if(storage_file_write(file, playlist->messages[i], strlen(playlist->messages[i])) !=
-           strlen(playlist->messages[i])) {
+        if (storage_file_write(file, playlist->messages[i], strlen(playlist->messages[i])) != strlen(playlist->messages[i]))
+        {
             FURI_LOG_E(TAG, "Failed to write playlist message %zu", i);
         }
 
         // Write a newline after each message
-        if(storage_file_write(file, "\n", 1) != 1) {
+        if (storage_file_write(file, "\n", 1) != 1)
+        {
             FURI_LOG_E(TAG, "Failed to write newline after message %zu", i);
         }
     }
@@ -44,20 +48,23 @@ void save_playlist(const PreSavedPlaylist* playlist) {
 }
 
 // Function to load the playlist
-// Function to load the playlist
-bool load_playlist(PreSavedPlaylist* playlist) {
+bool load_playlist(PreSavedPlaylist *playlist)
+{
     // Ensure playlist is not NULL
-    if(!playlist) {
+    if (!playlist)
+    {
         FURI_LOG_E(TAG, "Playlist is NULL");
         return false;
     }
 
     // Ensure playlist->messages is not NULL and allocate memory for each message
-    for(size_t i = 0; i < MAX_PRE_SAVED_MESSAGES; ++i) {
-        if(!playlist->messages[i]) // Check if memory is already allocated
+    for (size_t i = 0; i < MAX_PRE_SAVED_MESSAGES; ++i)
+    {
+        if (!playlist->messages[i]) // Check if memory is already allocated
         {
-            playlist->messages[i] = (char*)malloc(MAX_MESSAGE_LENGTH * sizeof(char));
-            if(!playlist->messages[i]) {
+            playlist->messages[i] = (char *)malloc(MAX_MESSAGE_LENGTH * sizeof(char));
+            if (!playlist->messages[i])
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for message %zu", i);
                 return false; // Return false on memory allocation failure
             }
@@ -65,14 +72,12 @@ bool load_playlist(PreSavedPlaylist* playlist) {
     }
 
     // Open the storage
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    File* file = storage_file_alloc(storage);
-
-    if(!storage_file_open(file, PRE_SAVED_MESSAGES_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
-        FURI_LOG_E(
-            TAG,
-            "Failed to open pre-saved messages file for reading: %s",
-            PRE_SAVED_MESSAGES_PATH);
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    File *file = storage_file_alloc(storage);
+
+    if (!storage_file_open(file, PRE_SAVED_MESSAGES_PATH, FSAM_READ, FSOM_OPEN_EXISTING))
+    {
+        FURI_LOG_E(TAG, "Failed to open pre-saved messages file for reading: %s", PRE_SAVED_MESSAGES_PATH);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
         return false; // Return false if the file does not exist
@@ -86,36 +91,39 @@ bool load_playlist(PreSavedPlaylist* playlist) {
     size_t message_pos = 0;
     bool message_started = false;
 
-    while(storage_file_read(file, &ch, 1) == 1) // Read one character at a time
+    while (storage_file_read(file, &ch, 1) == 1) // Read one character at a time
     {
         message_started = true;
 
-        if(ch == '\n' ||
-           message_pos >= (MAX_MESSAGE_LENGTH - 1)) // End of line or message is too long
+        if (ch == '\n' || message_pos >= (MAX_MESSAGE_LENGTH - 1)) // End of line or message is too long
         {
             playlist->messages[playlist->count][message_pos] = '\0'; // Null-terminate the message
-            playlist->count++; // Move to the next message
-            message_pos = 0; // Reset for the next message
+            playlist->count++;                                       // Move to the next message
+            message_pos = 0;                                         // Reset for the next message
             message_started = false;
 
             // Ensure the playlist count does not exceed the maximum
-            if(playlist->count >= MAX_PRE_SAVED_MESSAGES) {
+            if (playlist->count >= MAX_PRE_SAVED_MESSAGES)
+            {
                 FURI_LOG_W(TAG, "Reached maximum playlist messages");
                 break;
             }
-        } else {
-            playlist->messages[playlist->count][message_pos++] =
-                ch; // Add character to current message
+        }
+        else
+        {
+            playlist->messages[playlist->count][message_pos++] = ch; // Add character to current message
         }
     }
 
     // Handle the case where the last message does not end with a newline
-    if(message_started && message_pos > 0) {
+    if (message_started && message_pos > 0)
+    {
         playlist->messages[playlist->count][message_pos] = '\0'; // Null-terminate the last message
-        playlist->count++; // Increment the count for the last message
+        playlist->count++;                                       // Increment the count for the last message
 
         // Ensure the playlist count does not exceed the maximum
-        if(playlist->count >= MAX_PRE_SAVED_MESSAGES) {
+        if (playlist->count >= MAX_PRE_SAVED_MESSAGES)
+        {
             FURI_LOG_W(TAG, "Reached maximum playlist messages");
         }
     }
@@ -128,25 +136,27 @@ bool load_playlist(PreSavedPlaylist* playlist) {
     return true;
 }
 void save_settings(
-    const char* ssid,
-    const char* password,
-    const char* login_username_logged_out,
-    const char* login_username_logged_in,
-    const char* login_password_logged_out,
-    const char* change_password_logged_in,
-    const char* is_logged_in) {
+    const char *ssid,
+    const char *password,
+    const char *login_username_logged_out,
+    const char *login_username_logged_in,
+    const char *login_password_logged_out,
+    const char *change_password_logged_in,
+    const char *change_bio_logged_in,
+    const char *is_logged_in)
+{
     // Create the directory for saving settings
     char directory_path[128];
-    snprintf(
-        directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social");
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social");
 
     // Create the directory
-    Storage* storage = furi_record_open(RECORD_STORAGE);
+    Storage *storage = furi_record_open(RECORD_STORAGE);
     storage_common_mkdir(storage, directory_path);
 
     // Open the settings file
-    File* file = storage_file_alloc(storage);
-    if(!storage_file_open(file, SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
+    File *file = storage_file_alloc(storage);
+    if (!storage_file_open(file, SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
         FURI_LOG_E(TAG, "Failed to open settings file for writing: %s", SETTINGS_PATH);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
@@ -155,82 +165,96 @@ void save_settings(
 
     // Save the ssid length and data
     size_t ssid_length = strlen(ssid) + 1; // Include null terminator
-    if(storage_file_write(file, &ssid_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, ssid, ssid_length) != ssid_length) {
+    if (storage_file_write(file, &ssid_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, ssid, ssid_length) != ssid_length)
+    {
         FURI_LOG_E(TAG, "Failed to write SSID");
     }
 
     // Save the password length and data
     size_t password_length = strlen(password) + 1; // Include null terminator
-    if(storage_file_write(file, &password_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, password, password_length) != password_length) {
+    if (storage_file_write(file, &password_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, password, password_length) != password_length)
+    {
         FURI_LOG_E(TAG, "Failed to write password");
     }
 
     // Save the login_username_logged_out length and data
     size_t username_out_length = strlen(login_username_logged_out) + 1; // Include null terminator
-    if(storage_file_write(file, &username_out_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, login_username_logged_out, username_out_length) !=
-           username_out_length) {
+    if (storage_file_write(file, &username_out_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, login_username_logged_out, username_out_length) != username_out_length)
+    {
         FURI_LOG_E(TAG, "Failed to write login_username_logged_out");
     }
 
     // Save the login_username_logged_in length and data
     size_t username_in_length = strlen(login_username_logged_in) + 1; // Include null terminator
-    if(storage_file_write(file, &username_in_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, login_username_logged_in, username_in_length) !=
-           username_in_length) {
+    if (storage_file_write(file, &username_in_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, login_username_logged_in, username_in_length) != username_in_length)
+    {
         FURI_LOG_E(TAG, "Failed to write login_username_logged_in");
     }
 
     // Save the login_password_logged_out length and data
     size_t password_out_length = strlen(login_password_logged_out) + 1; // Include null terminator
-    if(storage_file_write(file, &password_out_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, login_password_logged_out, password_out_length) !=
-           password_out_length) {
+    if (storage_file_write(file, &password_out_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, login_password_logged_out, password_out_length) != password_out_length)
+    {
         FURI_LOG_E(TAG, "Failed to write login_password_logged_out");
     }
 
     // Save the change_password_logged_in length and data
-    size_t change_password_length =
-        strlen(change_password_logged_in) + 1; // Include null terminator
-    if(storage_file_write(file, &change_password_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, change_password_logged_in, change_password_length) !=
-           change_password_length) {
+    size_t change_password_length = strlen(change_password_logged_in) + 1; // Include null terminator
+    if (storage_file_write(file, &change_password_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, change_password_logged_in, change_password_length) != change_password_length)
+    {
         FURI_LOG_E(TAG, "Failed to write change_password_logged_in");
     }
 
     // Save the is_logged_in length and data
     size_t is_logged_in_length = strlen(is_logged_in) + 1; // Include null terminator
-    if(storage_file_write(file, &is_logged_in_length, sizeof(size_t)) != sizeof(size_t) ||
-       storage_file_write(file, is_logged_in, is_logged_in_length) != is_logged_in_length) {
+    if (storage_file_write(file, &is_logged_in_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, is_logged_in, is_logged_in_length) != is_logged_in_length)
+    {
         FURI_LOG_E(TAG, "Failed to write is_logged_in");
     }
 
+    // Save the change_bio_logged_in length and data
+    size_t change_bio_length = strlen(change_bio_logged_in) + 1; // Include null terminator
+    if (storage_file_write(file, &change_bio_length, sizeof(size_t)) != sizeof(size_t) ||
+        storage_file_write(file, change_bio_logged_in, change_bio_length) != change_bio_length)
+    {
+        FURI_LOG_E(TAG, "Failed to write change_bio_logged_in");
+    }
+
     storage_file_close(file);
     storage_file_free(file);
     furi_record_close(RECORD_STORAGE);
 }
 
 bool load_settings(
-    char* ssid,
+    char *ssid,
     size_t ssid_size,
-    char* password,
+    char *password,
     size_t password_size,
-    char* login_username_logged_out,
+    char *login_username_logged_out,
     size_t username_out_size,
-    char* login_username_logged_in,
+    char *login_username_logged_in,
     size_t username_in_size,
-    char* login_password_logged_out,
+    char *login_password_logged_out,
     size_t password_out_size,
-    char* change_password_logged_in,
+    char *change_password_logged_in,
     size_t change_password_size,
-    char* is_logged_in,
-    size_t is_logged_in_size) {
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    File* file = storage_file_alloc(storage);
-
-    if(!storage_file_open(file, SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
+    char *change_bio_logged_in,
+    size_t change_bio_size,
+    char *is_logged_in,
+    size_t is_logged_in_size)
+{
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    File *file = storage_file_alloc(storage);
+
+    if (!storage_file_open(file, SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING))
+    {
         FURI_LOG_E(TAG, "Failed to open settings file for reading: %s", SETTINGS_PATH);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
@@ -239,108 +263,166 @@ bool load_settings(
 
     // Load the ssid
     size_t ssid_length;
-    if(storage_file_read(file, &ssid_length, sizeof(size_t)) != sizeof(size_t) ||
-       ssid_length > ssid_size || storage_file_read(file, ssid, ssid_length) != ssid_length) {
+    if (storage_file_read(file, &ssid_length, sizeof(size_t)) != sizeof(size_t) || ssid_length > ssid_size ||
+        storage_file_read(file, ssid, ssid_length) != ssid_length)
+    {
         FURI_LOG_E(TAG, "Failed to read SSID");
         storage_file_close(file);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
         return false;
-    } else {
+    }
+    else
+    {
         ssid[ssid_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the password
     size_t password_length;
-    if(storage_file_read(file, &password_length, sizeof(size_t)) != sizeof(size_t) ||
-       password_length > password_size ||
-       storage_file_read(file, password, password_length) != password_length) {
+    if (storage_file_read(file, &password_length, sizeof(size_t)) != sizeof(size_t) || password_length > password_size ||
+        storage_file_read(file, password, password_length) != password_length)
+    {
         FURI_LOG_E(TAG, "Failed to read password");
         storage_file_close(file);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
         return false;
-    } else {
+    }
+    else
+    {
         password[password_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the login_username_logged_out
     size_t username_out_length;
-    if(storage_file_read(file, &username_out_length, sizeof(size_t)) != sizeof(size_t) ||
-       username_out_length > username_out_size ||
-       storage_file_read(file, login_username_logged_out, username_out_length) !=
-           username_out_length) {
+    if (storage_file_read(file, &username_out_length, sizeof(size_t)) != sizeof(size_t) || username_out_length > username_out_size ||
+        storage_file_read(file, login_username_logged_out, username_out_length) != username_out_length)
+    {
         FURI_LOG_E(TAG, "Failed to read login_username_logged_out");
         // storage_file_close(file);
         // storage_file_free(file);
         // furi_record_close(RECORD_STORAGE);
         // return false;
-    } else {
+    }
+    else
+    {
         login_username_logged_out[username_out_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the login_username_logged_in
     size_t username_in_length;
-    if(storage_file_read(file, &username_in_length, sizeof(size_t)) != sizeof(size_t) ||
-       username_in_length > username_in_size ||
-       storage_file_read(file, login_username_logged_in, username_in_length) !=
-           username_in_length) {
+    if (storage_file_read(file, &username_in_length, sizeof(size_t)) != sizeof(size_t) || username_in_length > username_in_size ||
+        storage_file_read(file, login_username_logged_in, username_in_length) != username_in_length)
+    {
         FURI_LOG_E(TAG, "Failed to read login_username_logged_in");
         // storage_file_close(file);
         // storage_file_free(file);
         // furi_record_close(RECORD_STORAGE);
         // return false;
-    } else {
+    }
+    else
+    {
         login_username_logged_in[username_in_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the login_password_logged_out
     size_t password_out_length;
-    if(storage_file_read(file, &password_out_length, sizeof(size_t)) != sizeof(size_t) ||
-       password_out_length > password_out_size ||
-       storage_file_read(file, login_password_logged_out, password_out_length) !=
-           password_out_length) {
+    if (storage_file_read(file, &password_out_length, sizeof(size_t)) != sizeof(size_t) || password_out_length > password_out_size ||
+        storage_file_read(file, login_password_logged_out, password_out_length) != password_out_length)
+    {
         FURI_LOG_E(TAG, "Failed to read login_password_logged_out");
         // storage_file_close(file);
         // storage_file_free(file);
         // furi_record_close(RECORD_STORAGE);
         // return false;
-    } else {
+    }
+    else
+    {
         login_password_logged_out[password_out_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the change_password_logged_in
     size_t change_password_length;
-    if(storage_file_read(file, &change_password_length, sizeof(size_t)) != sizeof(size_t) ||
-       change_password_length > change_password_size ||
-       storage_file_read(file, change_password_logged_in, change_password_length) !=
-           change_password_length) {
+    if (storage_file_read(file, &change_password_length, sizeof(size_t)) != sizeof(size_t) || change_password_length > change_password_size ||
+        storage_file_read(file, change_password_logged_in, change_password_length) != change_password_length)
+    {
         FURI_LOG_E(TAG, "Failed to read change_password_logged_in");
         // storage_file_close(file);
         // storage_file_free(file);
         // furi_record_close(RECORD_STORAGE);
         //  return false;
-    } else {
+    }
+    else
+    {
         change_password_logged_in[change_password_length - 1] = '\0'; // Ensure null-termination
     }
 
     // Load the is_logged_in
     size_t is_logged_in_length;
-    if(storage_file_read(file, &is_logged_in_length, sizeof(size_t)) != sizeof(size_t) ||
-       is_logged_in_length > is_logged_in_size ||
-       storage_file_read(file, is_logged_in, is_logged_in_length) != is_logged_in_length) {
+    if (storage_file_read(file, &is_logged_in_length, sizeof(size_t)) != sizeof(size_t) || is_logged_in_length > is_logged_in_size ||
+        storage_file_read(file, is_logged_in, is_logged_in_length) != is_logged_in_length)
+    {
         FURI_LOG_E(TAG, "Failed to read is_logged_in");
         // storage_file_close(file);
         // storage_file_free(file);
         // furi_record_close(RECORD_STORAGE);
         //  return false;
-    } else {
+    }
+    else
+    {
         is_logged_in[is_logged_in_length - 1] = '\0'; // Ensure null-termination
     }
 
+    // Load the change_bio_logged_in
+    size_t change_bio_length;
+    if (storage_file_read(file, &change_bio_length, sizeof(size_t)) != sizeof(size_t) || change_bio_length > change_bio_size ||
+        storage_file_read(file, change_bio_logged_in, change_bio_length) != change_bio_length)
+    {
+        FURI_LOG_E(TAG, "Failed to read change_bio_logged_in");
+        // storage_file_close(file);
+        // storage_file_free(file);
+        // furi_record_close(RECORD_STORAGE);
+        //  return false;
+    }
+    else
+    {
+        change_bio_logged_in[change_bio_length - 1] = '\0'; // Ensure null-termination
+    }
+
     storage_file_close(file);
     storage_file_free(file);
     furi_record_close(RECORD_STORAGE);
 
     return true;
 }
+
+bool flip_social_save_post(char *post_id, char *json_feed_data)
+{
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    File *file = storage_file_alloc(storage);
+
+    char file_path[128];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed_post_%s.json", post_id);
+
+    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
+        FURI_LOG_E(TAG, "Failed to open file for writing: %s", file_path);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    if (storage_file_write(file, json_feed_data, strlen(json_feed_data)) != strlen(json_feed_data))
+    {
+        FURI_LOG_E(TAG, "Failed to write feed post data");
+        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;
+}

+ 21 - 17
flip_social/flip_storage/flip_social_storage.h

@@ -4,34 +4,38 @@
 #include "flip_social.h"
 
 // Function to save the playlist
-void save_playlist(const PreSavedPlaylist* playlist);
+void save_playlist(const PreSavedPlaylist *playlist);
 
 // Function to load the playlist
-bool load_playlist(PreSavedPlaylist* playlist);
+bool load_playlist(PreSavedPlaylist *playlist);
 
 void save_settings(
-    const char* ssid,
-    const char* password,
-    const char* login_username_logged_out,
-    const char* login_username_logged_in,
-    const char* login_password_logged_out,
-    const char* change_password_logged_in,
-    const char* is_logged_in);
+    const char *ssid,
+    const char *password,
+    const char *login_username_logged_out,
+    const char *login_username_logged_in,
+    const char *login_password_logged_out,
+    const char *change_password_logged_in,
+    const char *change_bio_logged_in,
+    const char *is_logged_in);
 
 bool load_settings(
-    char* ssid,
+    char *ssid,
     size_t ssid_size,
-    char* password,
+    char *password,
     size_t password_size,
-    char* login_username_logged_out,
+    char *login_username_logged_out,
     size_t username_out_size,
-    char* login_username_logged_in,
+    char *login_username_logged_in,
     size_t username_in_size,
-    char* login_password_logged_out,
+    char *login_password_logged_out,
     size_t password_out_size,
-    char* change_password_logged_in,
+    char *change_password_logged_in,
     size_t change_password_size,
-    char* is_logged_in,
+    char *change_bio_logged_in,
+    size_t change_bio_size,
+    char *is_logged_in,
     size_t is_logged_in_size);
 
-#endif
+bool flip_social_save_post(char *post_id, char *json_feed_data);
+#endif

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 291 - 165
flip_social/flipper_http/flipper_http.c


+ 98 - 60
flip_social/flipper_http/flipper_http.h

@@ -2,6 +2,10 @@
 #ifndef FLIPPER_HTTP_H
 #define FLIPPER_HTTP_H
 
+#include <gui/gui.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+#include <gui/modules/loading.h>
 #include <furi.h>
 #include <furi_hal.h>
 #include <furi_hal_gpio.h>
@@ -11,69 +15,72 @@
 
 // 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 (5 * 1000) // 5 seconds
-#define BAUDRATE               (115200) // UART baudrate
-#define RX_BUF_SIZE            1024 // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE    8192 // UART RX line buffer size (increase for large responses)
-#define MAX_FILE_SHOW          8192 // Maximum data from file to show
-#define FILE_BUFFER_SIZE       512 // File buffer size
+#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 128                   // 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
 
 // 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
+    SENDING,   // Sending data
+    ISSUE,     // Issue with connection
 } SerialState;
 
 // Event Flags for UART Worker Thread
-typedef enum {
+typedef enum
+{
     WorkerEvtStop = (1 << 0),
     WorkerEvtRxDone = (1 << 1),
 } WorkerEvtFlags;
 
 // 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
+    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;
+    char *last_response;
     char file_path[256]; // Path to save the received data
 
     // Timer-related members
-    FuriTimer* get_timeout_timer; // Timer for HTTP request timeout
+    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 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 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 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
+    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;
+    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
+    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
 } FlipperHTTP;
@@ -89,12 +96,12 @@ extern size_t file_buffer_len;
 // 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,
+    const void *data,
     size_t data_size,
     bool start_new_file,
-    char* file_path);
+    char *file_path);
 
-FuriString* flipper_http_load_from_file(char* file_path);
+FuriString *flipper_http_load_from_file(char *file_path);
 
 // UART worker thread
 /**
@@ -104,7 +111,7 @@ FuriString* flipper_http_load_from_file(char* file_path);
  * @note       This function will handle received data asynchronously via the callback.
  */
 // UART worker thread
-int32_t flipper_http_worker(void* context);
+int32_t flipper_http_worker(void *context);
 
 // Timer callback function
 /**
@@ -113,7 +120,7 @@ int32_t flipper_http_worker(void* context);
  * @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);
+void get_timeout_timer_callback(void *context);
 
 // UART RX Handler Callback (Interrupt Context)
 /**
@@ -125,9 +132,9 @@ void get_timeout_timer_callback(void* context);
  * @note       This function will handle received data asynchronously via the callback.
  */
 void _flipper_http_rx_callback(
-    FuriHalSerialHandle* handle,
+    FuriHalSerialHandle *handle,
     FuriHalSerialRxEvent event,
-    void* context);
+    void *context);
 
 // UART initialization function
 /**
@@ -137,7 +144,7 @@ void _flipper_http_rx_callback(
  * @param      context   The context to pass to the callback.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_init(FlipperHTTP_Callback callback, void* context);
+bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
 
 // Deinitialize UART
 /**
@@ -154,7 +161,7 @@ void flipper_http_deinit();
  * @param      data  The data to send over UART.
  * @note       The data will be sent over UART with a newline character appended.
  */
-bool flipper_http_send_data(const char* data);
+bool flipper_http_send_data(const char *data);
 
 // Function to send a PING request
 /**
@@ -198,7 +205,7 @@ bool flipper_http_led_off();
  * @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(const char *key, const char *json_data);
 
 // Function to parse JSON array data
 /**
@@ -209,7 +216,7 @@ bool flipper_http_parse_json(const char* key, const char* json_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);
+bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
 
 // Function to scan for WiFi networks
 /**
@@ -225,7 +232,7 @@ bool flipper_http_scan_wifi();
  * @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_save_wifi(const char *ssid, const char *password);
 
 // Function to get IP address of WiFi Devboard
 /**
@@ -266,7 +273,7 @@ bool flipper_http_connect_wifi();
  * @param      url  The URL to send the GET request to.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_get_request(const char* url);
+bool flipper_http_get_request(const char *url);
 
 // Function to send a GET request with headers
 /**
@@ -276,7 +283,7 @@ bool flipper_http_get_request(const char* url);
  * @param      headers  The headers to send with the GET 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_get_request_with_headers(const char *url, const char *headers);
 
 // Function to send a GET request with headers and return bytes
 /**
@@ -286,7 +293,7 @@ bool flipper_http_get_request_with_headers(const char* url, const char* headers)
  * @param      headers  The headers to send with the GET request.
  * @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_get_request_bytes(const char *url, const char *headers);
 
 // Function to send a POST request with headers
 /**
@@ -298,9 +305,9 @@ bool flipper_http_get_request_bytes(const char* url, const char* headers);
  * @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);
+    const char *url,
+    const char *headers,
+    const char *payload);
 
 // Function to send a POST request with headers and return bytes
 /**
@@ -311,7 +318,7 @@ bool flipper_http_post_request_with_headers(
  * @param      payload  The data to send with the POST request.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_post_request_bytes(const char* url, const char* headers, const char* payload);
+bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
 
 // Function to send a PUT request with headers
 /**
@@ -323,9 +330,9 @@ bool flipper_http_post_request_bytes(const char* url, const char* headers, const
  * @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);
+    const char *url,
+    const char *headers,
+    const char *payload);
 
 // Function to send a DELETE request with headers
 /**
@@ -337,9 +344,9 @@ bool flipper_http_put_request_with_headers(
  * @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);
+    const char *url,
+    const char *headers,
+    const char *payload);
 
 // Function to handle received data asynchronously
 /**
@@ -349,10 +356,10 @@ bool flipper_http_delete_request_with_headers(
  * @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);
+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);
+char *trim(const char *str);
 /**
  * @brief Process requests and parse JSON data asynchronously
  * @param http_request The function to send the request
@@ -360,5 +367,36 @@ char* trim(const char* str);
  * @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

+ 77 - 76
flip_social/friends/flip_social_friends.c

@@ -1,12 +1,16 @@
 #include "flip_social_friends.h"
 
-FlipSocialModel* flip_social_friends_alloc() {
+FlipSocialModel *flip_social_friends_alloc()
+{
     // Allocate memory for each username only if not already allocated
-    FlipSocialModel* friends = malloc(sizeof(FlipSocialModel));
-    for(size_t i = 0; i < MAX_FRIENDS; i++) {
-        if(friends->usernames[i] == NULL) {
+    FlipSocialModel *friends = malloc(sizeof(FlipSocialModel));
+    for (size_t i = 0; i < MAX_FRIENDS; i++)
+    {
+        if (friends->usernames[i] == NULL)
+        {
             friends->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(friends->usernames[i] == NULL) {
+            if (friends->usernames[i] == NULL)
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
                 return NULL; // Return false on memory allocation failure
             }
@@ -15,36 +19,32 @@ FlipSocialModel* flip_social_friends_alloc() {
     return friends;
 }
 
-void flip_social_free_friends() {
-    if(!flip_social_friends) {
-        FURI_LOG_E(TAG, "Friends model is NULL");
-        return;
-    }
-    for(int i = 0; i < flip_social_friends->count; i++) {
-        if(flip_social_friends->usernames[i]) {
-            free(flip_social_friends->usernames[i]);
-        }
-    }
-}
-
 // 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 flip_social_get_friends()
+{
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "App instance is NULL");
+        return false;
+    }
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
     // will return true unless the devboard is not connected
     char url[100];
     snprintf(
         fhttp.file_path,
         sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/friends.txt");
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/friends.json");
 
     fhttp.save_received_data = true;
     auth_headers_alloc();
-    snprintf(
-        url,
-        100,
-        "https://www.flipsocial.net/api/user/friends/%s/",
-        app_instance->login_username_logged_in);
-    if(!flipper_http_get_request_with_headers(url, auth_headers)) {
+    snprintf(url, sizeof(url), "https://www.flipsocial.net/api/user/friends/%s/", app_instance->login_username_logged_in);
+    if (!flipper_http_get_request_with_headers(url, auth_headers))
+    {
         FURI_LOG_E(TAG, "Failed to send HTTP request for friends");
         fhttp.state = ISSUE;
         return false;
@@ -53,38 +53,40 @@ bool flip_social_get_friends() {
     return true;
 }
 
-bool flip_social_update_friends() {
-    if(!app_instance->submenu_friends) {
+bool flip_social_update_friends()
+{
+    if (!app_instance->submenu_friends)
+    {
         FURI_LOG_E(TAG, "Friends submenu is NULL");
         return false;
     }
-    if(!flip_social_friends) {
+    if (!flip_social_friends)
+    {
         FURI_LOG_E(TAG, "Friends model is NULL");
         return false;
     }
     // Add submenu items for the users
     submenu_reset(app_instance->submenu_friends);
     submenu_set_header(app_instance->submenu_friends, "Friends");
-    for(int i = 0; i < flip_social_friends->count; i++) {
-        submenu_add_item(
-            app_instance->submenu_friends,
-            flip_social_friends->usernames[i],
-            FlipSocialSubmenuLoggedInIndexFriendsStart + i,
-            flip_social_callback_submenu_choices,
-            app_instance);
+    for (int i = 0; i < flip_social_friends->count; i++)
+    {
+        submenu_add_item(app_instance->submenu_friends, flip_social_friends->usernames[i], FlipSocialSubmenuLoggedInIndexFriendsStart + i, flip_social_callback_submenu_choices, app_instance);
     }
     return true;
 }
 
-bool flip_social_parse_json_friends() {
+bool flip_social_parse_json_friends()
+{
     // load the received data from the saved file
-    FuriString* friend_data = flipper_http_load_from_file(fhttp.file_path);
-    if(friend_data == NULL) {
+    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.");
         return false;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(friend_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(friend_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(friend_data);
         return false;
@@ -92,7 +94,8 @@ bool flip_social_parse_json_friends() {
 
     // Allocate memory for each username only if not already allocated
     flip_social_friends = flip_social_friends_alloc();
-    if(flip_social_friends == NULL) {
+    if (flip_social_friends == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for friends usernames.");
         furi_string_free(friend_data);
         free(data_cstr);
@@ -100,17 +103,23 @@ bool flip_social_parse_json_friends() {
     }
 
     // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
+    char *pos = data_cstr;
+    while ((pos = strchr(pos, '\n')) != NULL)
+    {
         *pos = ' ';
     }
 
     // Initialize friends count
     flip_social_friends->count = 0;
 
+    // Reset the friends submenu
+    submenu_reset(app_instance->submenu_friends);
+    submenu_set_header(app_instance->submenu_friends, "Friends");
+
     // Extract the users array from the JSON
-    char* json_users = get_json_value("friends", data_cstr, MAX_TOKENS);
-    if(json_users == NULL) {
+    char *json_users = get_json_value("friends", data_cstr, 128);
+    if (json_users == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to parse friends array.");
         furi_string_free(friend_data);
         free(data_cstr);
@@ -118,52 +127,44 @@ bool flip_social_parse_json_friends() {
     }
 
     // Manual tokenization for comma-separated values
-    char* start = json_users + 1; // Skip the opening bracket
-    char* end;
-    while((end = strchr(start, ',')) != NULL && flip_social_friends->count < MAX_FRIENDS) {
+    char *start = json_users + 1; // Skip the opening bracket
+    char *end;
+    while ((end = strchr(start, ',')) != NULL && flip_social_friends->count < MAX_FRIENDS)
+    {
         *end = '\0'; // Null-terminate the current token
 
         // Remove quotes
-        if(*start == '"') start++;
-        if(*(end - 1) == '"') *(end - 1) = '\0';
+        if (*start == '"')
+            start++;
+        if (*(end - 1) == '"')
+            *(end - 1) = '\0';
 
         // Copy username to pre-allocated memory
-        snprintf(
-            flip_social_friends->usernames[flip_social_friends->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+        snprintf(flip_social_friends->usernames[flip_social_friends->count], MAX_USER_LENGTH, "%s", start);
+        submenu_add_item(app_instance->submenu_friends, flip_social_friends->usernames[flip_social_friends->count], FlipSocialSubmenuLoggedInIndexFriendsStart + flip_social_friends->count, flip_social_callback_submenu_choices, app_instance);
         flip_social_friends->count++;
         start = end + 1;
     }
 
     // Handle the last token
-    if(*start != '\0' && flip_social_friends->count < MAX_FRIENDS) {
-        if(*start == '"') start++;
-        if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
-        if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
-
-        snprintf(
-            flip_social_friends->usernames[flip_social_friends->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+    if (*start != '\0' && flip_social_friends->count < MAX_FRIENDS)
+    {
+        if (*start == '"')
+            start++;
+        if (*(start + strlen(start) - 1) == ']')
+            *(start + strlen(start) - 1) = '\0';
+        if (*(start + strlen(start) - 1) == '"')
+            *(start + strlen(start) - 1) = '\0';
+
+        snprintf(flip_social_friends->usernames[flip_social_friends->count], MAX_USER_LENGTH, "%s", start);
+        submenu_add_item(app_instance->submenu_friends, flip_social_friends->usernames[flip_social_friends->count], FlipSocialSubmenuLoggedInIndexFriendsStart + flip_social_friends->count, flip_social_callback_submenu_choices, app_instance);
         flip_social_friends->count++;
     }
 
-    // Add submenu items for the friends
-    if(!flip_social_update_friends()) {
-        FURI_LOG_E(TAG, "Failed to update friends submenu");
-        furi_string_free(friend_data);
-        free(data_cstr);
-        return false;
-    }
-
-    // Free the json_users
+    furi_string_free(friend_data);
+    free(data_cstr);
     free(json_users);
     free(start);
     free(end);
-    furi_string_free(friend_data);
-    free(data_cstr);
     return true;
 }

+ 2 - 3
flip_social/friends/flip_social_friends.h

@@ -3,9 +3,8 @@
 #include "flip_social.h"
 #include <callback/flip_social_callback.h>
 
-FlipSocialModel* flip_social_friends_alloc();
-void flip_social_free_friends();
+FlipSocialModel *flip_social_friends_alloc();
 bool flip_social_get_friends();
 bool flip_social_update_friends();
 bool flip_social_parse_json_friends();
-#endif
+#endif

+ 217 - 136
flip_social/jsmn/jsmn.c

@@ -13,11 +13,13 @@
 /**
  * Allocates a fresh unused token from the token pool.
  */
-static jsmntok_t*
-    jsmn_alloc_token(jsmn_parser* parser, jsmntok_t* tokens, const size_t num_tokens) {
-    jsmntok_t* tok;
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+                                   const size_t num_tokens)
+{
+    jsmntok_t *tok;
 
-    if(parser->toknext >= num_tokens) {
+    if (parser->toknext >= num_tokens)
+    {
         return NULL;
     }
     tok = &tokens[parser->toknext++];
@@ -32,8 +34,9 @@ static jsmntok_t*
 /**
  * Fills token type and boundaries.
  */
-static void
-    jsmn_fill_token(jsmntok_t* token, const jsmntype_t type, const int start, const int end) {
+static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+                            const int start, const int end)
+{
     token->type = type;
     token->start = start;
     token->end = end;
@@ -43,19 +46,19 @@ static void
 /**
  * Fills next available token with JSON primitive.
  */
-static int jsmn_parse_primitive(
-    jsmn_parser* parser,
-    const char* js,
-    const size_t len,
-    jsmntok_t* tokens,
-    const size_t num_tokens) {
-    jsmntok_t* token;
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+                                const size_t len, jsmntok_t *tokens,
+                                const size_t num_tokens)
+{
+    jsmntok_t *token;
     int start;
 
     start = parser->pos;
 
-    for(; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
-        switch(js[parser->pos]) {
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+        switch (js[parser->pos])
+        {
 #ifndef JSMN_STRICT
         /* In strict mode primitive must be followed by "," or "}" or "]" */
         case ':':
@@ -72,7 +75,8 @@ static int jsmn_parse_primitive(
             /* to quiet a warning from gcc*/
             break;
         }
-        if(js[parser->pos] < 32 || js[parser->pos] >= 127) {
+        if (js[parser->pos] < 32 || js[parser->pos] >= 127)
+        {
             parser->pos = start;
             return JSMN_ERROR_INVAL;
         }
@@ -84,12 +88,14 @@ static int jsmn_parse_primitive(
 #endif
 
 found:
-    if(tokens == NULL) {
+    if (tokens == NULL)
+    {
         parser->pos--;
         return 0;
     }
     token = jsmn_alloc_token(parser, tokens, num_tokens);
-    if(token == NULL) {
+    if (token == NULL)
+    {
         parser->pos = start;
         return JSMN_ERROR_NOMEM;
     }
@@ -104,29 +110,31 @@ found:
 /**
  * Fills next token with JSON string.
  */
-static int jsmn_parse_string(
-    jsmn_parser* parser,
-    const char* js,
-    const size_t len,
-    jsmntok_t* tokens,
-    const size_t num_tokens) {
-    jsmntok_t* token;
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+                             const size_t len, jsmntok_t *tokens,
+                             const size_t num_tokens)
+{
+    jsmntok_t *token;
 
     int start = parser->pos;
 
     /* Skip starting quote */
     parser->pos++;
 
-    for(; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
         char c = js[parser->pos];
 
         /* Quote: end of string */
-        if(c == '\"') {
-            if(tokens == NULL) {
+        if (c == '\"')
+        {
+            if (tokens == NULL)
+            {
                 return 0;
             }
             token = jsmn_alloc_token(parser, tokens, num_tokens);
-            if(token == NULL) {
+            if (token == NULL)
+            {
                 parser->pos = start;
                 return JSMN_ERROR_NOMEM;
             }
@@ -138,10 +146,12 @@ static int jsmn_parse_string(
         }
 
         /* Backslash: Quoted symbol expected */
-        if(c == '\\' && parser->pos + 1 < len) {
+        if (c == '\\' && parser->pos + 1 < len)
+        {
             int i;
             parser->pos++;
-            switch(js[parser->pos]) {
+            switch (js[parser->pos])
+            {
             /* Allowed escaped symbols */
             case '\"':
             case '/':
@@ -155,11 +165,13 @@ static int jsmn_parse_string(
             /* Allows escaped symbol \uXXXX */
             case 'u':
                 parser->pos++;
-                for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
+                for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++)
+                {
                     /* If it isn't a hex character we have an error */
-                    if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
-                         (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
-                         (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+                    if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+                          (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+                          (js[parser->pos] >= 97 && js[parser->pos] <= 102)))
+                    { /* a-f */
                         parser->pos = start;
                         return JSMN_ERROR_INVAL;
                     }
@@ -181,7 +193,8 @@ static int jsmn_parse_string(
 /**
  * Create JSON parser over an array of tokens
  */
-void jsmn_init(jsmn_parser* parser) {
+void jsmn_init(jsmn_parser *parser)
+{
     parser->pos = 0;
     parser->toknext = 0;
     parser->toksuper = -1;
@@ -190,38 +203,41 @@ void jsmn_init(jsmn_parser* parser) {
 /**
  * Parse JSON string and fill tokens.
  */
-int jsmn_parse(
-    jsmn_parser* parser,
-    const char* js,
-    const size_t len,
-    jsmntok_t* tokens,
-    const unsigned int num_tokens) {
+int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+               jsmntok_t *tokens, const unsigned int num_tokens)
+{
     int r;
     int i;
-    jsmntok_t* token;
+    jsmntok_t *token;
     int count = parser->toknext;
 
-    for(; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
         char c;
         jsmntype_t type;
 
         c = js[parser->pos];
-        switch(c) {
+        switch (c)
+        {
         case '{':
         case '[':
             count++;
-            if(tokens == NULL) {
+            if (tokens == NULL)
+            {
                 break;
             }
             token = jsmn_alloc_token(parser, tokens, num_tokens);
-            if(token == NULL) {
+            if (token == NULL)
+            {
                 return JSMN_ERROR_NOMEM;
             }
-            if(parser->toksuper != -1) {
-                jsmntok_t* t = &tokens[parser->toksuper];
+            if (parser->toksuper != -1)
+            {
+                jsmntok_t *t = &tokens[parser->toksuper];
 #ifdef JSMN_STRICT
                 /* In strict mode an object or array can't become a key */
-                if(t->type == JSMN_OBJECT) {
+                if (t->type == JSMN_OBJECT)
+                {
                     return JSMN_ERROR_INVAL;
                 }
 #endif
@@ -236,26 +252,33 @@ int jsmn_parse(
             break;
         case '}':
         case ']':
-            if(tokens == NULL) {
+            if (tokens == NULL)
+            {
                 break;
             }
             type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
 #ifdef JSMN_PARENT_LINKS
-            if(parser->toknext < 1) {
+            if (parser->toknext < 1)
+            {
                 return JSMN_ERROR_INVAL;
             }
             token = &tokens[parser->toknext - 1];
-            for(;;) {
-                if(token->start != -1 && token->end == -1) {
-                    if(token->type != type) {
+            for (;;)
+            {
+                if (token->start != -1 && token->end == -1)
+                {
+                    if (token->type != type)
+                    {
                         return JSMN_ERROR_INVAL;
                     }
                     token->end = parser->pos + 1;
                     parser->toksuper = token->parent;
                     break;
                 }
-                if(token->parent == -1) {
-                    if(token->type != type || parser->toksuper == -1) {
+                if (token->parent == -1)
+                {
+                    if (token->type != type || parser->toksuper == -1)
+                    {
                         return JSMN_ERROR_INVAL;
                     }
                     break;
@@ -263,10 +286,13 @@ int jsmn_parse(
                 token = &tokens[token->parent];
             }
 #else
-            for(i = parser->toknext - 1; i >= 0; i--) {
+            for (i = parser->toknext - 1; i >= 0; i--)
+            {
                 token = &tokens[i];
-                if(token->start != -1 && token->end == -1) {
-                    if(token->type != type) {
+                if (token->start != -1 && token->end == -1)
+                {
+                    if (token->type != type)
+                    {
                         return JSMN_ERROR_INVAL;
                     }
                     parser->toksuper = -1;
@@ -275,12 +301,15 @@ int jsmn_parse(
                 }
             }
             /* Error if unmatched closing bracket */
-            if(i == -1) {
+            if (i == -1)
+            {
                 return JSMN_ERROR_INVAL;
             }
-            for(; i >= 0; i--) {
+            for (; i >= 0; i--)
+            {
                 token = &tokens[i];
-                if(token->start != -1 && token->end == -1) {
+                if (token->start != -1 && token->end == -1)
+                {
                     parser->toksuper = i;
                     break;
                 }
@@ -289,11 +318,13 @@ int jsmn_parse(
             break;
         case '\"':
             r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
-            if(r < 0) {
+            if (r < 0)
+            {
                 return r;
             }
             count++;
-            if(parser->toksuper != -1 && tokens != NULL) {
+            if (parser->toksuper != -1 && tokens != NULL)
+            {
                 tokens[parser->toksuper].size++;
             }
             break;
@@ -306,15 +337,19 @@ int jsmn_parse(
             parser->toksuper = parser->toknext - 1;
             break;
         case ',':
-            if(tokens != NULL && parser->toksuper != -1 &&
-               tokens[parser->toksuper].type != JSMN_ARRAY &&
-               tokens[parser->toksuper].type != JSMN_OBJECT) {
+            if (tokens != NULL && parser->toksuper != -1 &&
+                tokens[parser->toksuper].type != JSMN_ARRAY &&
+                tokens[parser->toksuper].type != JSMN_OBJECT)
+            {
 #ifdef JSMN_PARENT_LINKS
                 parser->toksuper = tokens[parser->toksuper].parent;
 #else
-                for(i = parser->toknext - 1; i >= 0; i--) {
-                    if(tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
-                        if(tokens[i].start != -1 && tokens[i].end == -1) {
+                for (i = parser->toknext - 1; i >= 0; i--)
+                {
+                    if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT)
+                    {
+                        if (tokens[i].start != -1 && tokens[i].end == -1)
+                        {
                             parser->toksuper = i;
                             break;
                         }
@@ -340,9 +375,12 @@ int jsmn_parse(
         case 'f':
         case 'n':
             /* And they must not be keys of the object */
-            if(tokens != NULL && parser->toksuper != -1) {
-                const jsmntok_t* t = &tokens[parser->toksuper];
-                if(t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) {
+            if (tokens != NULL && parser->toksuper != -1)
+            {
+                const jsmntok_t *t = &tokens[parser->toksuper];
+                if (t->type == JSMN_OBJECT ||
+                    (t->type == JSMN_STRING && t->size != 0))
+                {
                     return JSMN_ERROR_INVAL;
                 }
             }
@@ -351,11 +389,13 @@ int jsmn_parse(
         default:
 #endif
             r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
-            if(r < 0) {
+            if (r < 0)
+            {
                 return r;
             }
             count++;
-            if(parser->toksuper != -1 && tokens != NULL) {
+            if (parser->toksuper != -1 && tokens != NULL)
+            {
                 tokens[parser->toksuper].size++;
             }
             break;
@@ -368,10 +408,13 @@ int jsmn_parse(
         }
     }
 
-    if(tokens != NULL) {
-        for(i = parser->toknext - 1; i >= 0; i--) {
+    if (tokens != NULL)
+    {
+        for (i = parser->toknext - 1; i >= 0; i--)
+        {
             /* Unmatched opened object or array */
-            if(tokens[i].start != -1 && tokens[i].end == -1) {
+            if (tokens[i].start != -1 && tokens[i].end == -1)
+            {
                 return JSMN_ERROR_PART;
             }
         }
@@ -381,10 +424,12 @@ int jsmn_parse(
 }
 
 // Helper function to create a JSON object
-char* jsmn(const char* key, const char* value) {
-    int length = strlen(key) + strlen(value) + 8; // Calculate required length
-    char* result = (char*)malloc(length * sizeof(char)); // Allocate memory
-    if(result == NULL) {
+char *jsmn(const char *key, const char *value)
+{
+    int length = strlen(key) + strlen(value) + 8;         // Calculate required length
+    char *result = (char *)malloc(length * sizeof(char)); // Allocate memory
+    if (result == NULL)
+    {
         return NULL; // Handle memory allocation failure
     }
     snprintf(result, length, "{\"%s\":\"%s\"}", key, value);
@@ -392,30 +437,36 @@ char* jsmn(const char* key, const char* value) {
 }
 
 // Helper function to compare JSON keys
-int jsoneq(const char* json, jsmntok_t* tok, const char* s) {
-    if(tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
-       strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
+int jsoneq(const char *json, jsmntok_t *tok, const char *s)
+{
+    if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
+        strncmp(json + tok->start, s, tok->end - tok->start) == 0)
+    {
         return 0;
     }
     return -1;
 }
 
 // Return the value of the key in the JSON data
-char* get_json_value(char* key, char* json_data, uint32_t max_tokens) {
+char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
+{
     // Parse the JSON feed
-    if(json_data != NULL) {
+    if (json_data != NULL)
+    {
         jsmn_parser parser;
         jsmn_init(&parser);
 
         // Allocate tokens array on the heap
-        jsmntok_t* tokens = malloc(sizeof(jsmntok_t) * max_tokens);
-        if(tokens == NULL) {
+        jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+        if (tokens == NULL)
+        {
             FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
             return NULL;
         }
 
         int ret = jsmn_parse(&parser, json_data, strlen(json_data), tokens, max_tokens);
-        if(ret < 0) {
+        if (ret < 0)
+        {
             // Handle parsing errors
             FURI_LOG_E("JSMM.H", "Failed to parse JSON: %d", ret);
             free(tokens);
@@ -423,19 +474,23 @@ char* get_json_value(char* key, char* json_data, uint32_t max_tokens) {
         }
 
         // Ensure that the root element is an object
-        if(ret < 1 || tokens[0].type != JSMN_OBJECT) {
+        if (ret < 1 || tokens[0].type != JSMN_OBJECT)
+        {
             FURI_LOG_E("JSMM.H", "Root element is not an object.");
             free(tokens);
             return NULL;
         }
 
         // Loop through the tokens to find the key
-        for(int i = 1; i < ret; i++) {
-            if(jsoneq(json_data, &tokens[i], key) == 0) {
+        for (int i = 1; i < ret; i++)
+        {
+            if (jsoneq(json_data, &tokens[i], key) == 0)
+            {
                 // We found the key. Now, return the associated value.
                 int length = tokens[i + 1].end - tokens[i + 1].start;
-                char* value = malloc(length + 1);
-                if(value == NULL) {
+                char *value = malloc(length + 1);
+                if (value == NULL)
+                {
                     FURI_LOG_E("JSMM.H", "Failed to allocate memory for value.");
                     free(tokens);
                     return NULL;
@@ -450,7 +505,9 @@ char* get_json_value(char* key, char* json_data, uint32_t max_tokens) {
 
         // Free the token array if key was not found
         free(tokens);
-    } else {
+    }
+    else
+    {
         FURI_LOG_E("JSMM.H", "JSON data is NULL");
     }
     FURI_LOG_E("JSMM.H", "Failed to find the key in the JSON.");
@@ -458,10 +515,12 @@ char* get_json_value(char* key, char* json_data, uint32_t max_tokens) {
 }
 
 // Revised get_json_array_value function
-char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t max_tokens) {
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
+{
     // Retrieve the array string for the given key
-    char* array_str = get_json_value(key, json_data, max_tokens);
-    if(array_str == NULL) {
+    char *array_str = get_json_value(key, json_data, max_tokens);
+    if (array_str == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
         return NULL;
     }
@@ -471,8 +530,9 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
     jsmn_init(&parser);
 
     // Allocate memory for JSON tokens
-    jsmntok_t* tokens = malloc(sizeof(jsmntok_t) * max_tokens);
-    if(tokens == NULL) {
+    jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+    if (tokens == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
         free(array_str);
         return NULL;
@@ -480,7 +540,8 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
 
     // Parse the JSON array
     int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
-    if(ret < 0) {
+    if (ret < 0)
+    {
         FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
         free(tokens);
         free(array_str);
@@ -488,7 +549,8 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
     }
 
     // Ensure the root element is an array
-    if(ret < 1 || tokens[0].type != JSMN_ARRAY) {
+    if (ret < 1 || tokens[0].type != JSMN_ARRAY)
+    {
         FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
         free(tokens);
         free(array_str);
@@ -496,12 +558,9 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
     }
 
     // Check if the index is within bounds
-    if(index >= (uint32_t)tokens[0].size) {
-        FURI_LOG_E(
-            "JSMM.H",
-            "Index %lu out of bounds for array with size %d.",
-            (unsigned long)index,
-            tokens[0].size);
+    if (index >= (uint32_t)tokens[0].size)
+    {
+        FURI_LOG_E("JSMM.H", "Index %lu out of bounds for array with size %d.", (unsigned long)index, tokens[0].size);
         free(tokens);
         free(array_str);
         return NULL;
@@ -509,20 +568,27 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
 
     // Locate the token corresponding to the desired array element
     int current_token = 1; // Start after the array token
-    for(uint32_t i = 0; i < index; i++) {
-        if(tokens[current_token].type == JSMN_OBJECT) {
+    for (uint32_t i = 0; i < index; i++)
+    {
+        if (tokens[current_token].type == JSMN_OBJECT)
+        {
             // For objects, skip all key-value pairs
             current_token += 1 + 2 * tokens[current_token].size;
-        } else if(tokens[current_token].type == JSMN_ARRAY) {
+        }
+        else if (tokens[current_token].type == JSMN_ARRAY)
+        {
             // For nested arrays, skip all elements
             current_token += 1 + tokens[current_token].size;
-        } else {
+        }
+        else
+        {
             // For primitive types, simply move to the next token
             current_token += 1;
         }
 
         // Safety check to prevent out-of-bounds
-        if(current_token >= ret) {
+        if (current_token >= ret)
+        {
             FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
             free(tokens);
             free(array_str);
@@ -533,8 +599,9 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
     // Extract the array element
     jsmntok_t element = tokens[current_token];
     int length = element.end - element.start;
-    char* value = malloc(length + 1);
-    if(value == NULL) {
+    char *value = malloc(length + 1);
+    if (value == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
         free(tokens);
         free(array_str);
@@ -553,10 +620,12 @@ char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t
 }
 
 // Revised get_json_array_values function with correct token skipping
-char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, int* num_values) {
+char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values)
+{
     // Retrieve the array string for the given key
-    char* array_str = get_json_value(key, json_data, max_tokens);
-    if(array_str == NULL) {
+    char *array_str = get_json_value(key, json_data, max_tokens);
+    if (array_str == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
         return NULL;
     }
@@ -566,8 +635,9 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
     jsmn_init(&parser);
 
     // Allocate memory for JSON tokens
-    jsmntok_t* tokens = malloc(sizeof(jsmntok_t) * max_tokens); // Allocate on the heap
-    if(tokens == NULL) {
+    jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens); // Allocate on the heap
+    if (tokens == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
         free(array_str);
         return NULL;
@@ -575,7 +645,8 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
 
     // Parse the JSON array
     int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
-    if(ret < 0) {
+    if (ret < 0)
+    {
         FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
         free(tokens);
         free(array_str);
@@ -583,7 +654,8 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
     }
 
     // Ensure the root element is an array
-    if(tokens[0].type != JSMN_ARRAY) {
+    if (tokens[0].type != JSMN_ARRAY)
+    {
         FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
         free(tokens);
         free(array_str);
@@ -592,8 +664,9 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
 
     // Allocate memory for the array of values (maximum possible)
     int array_size = tokens[0].size;
-    char** values = malloc(array_size * sizeof(char*));
-    if(values == NULL) {
+    char **values = malloc(array_size * sizeof(char *));
+    if (values == NULL)
+    {
         FURI_LOG_E("JSMM.H", "Failed to allocate memory for array of values.");
         free(tokens);
         free(array_str);
@@ -604,15 +677,18 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
 
     // Traverse the array and extract all object values
     int current_token = 1; // Start after the array token
-    for(int i = 0; i < array_size; i++) {
-        if(current_token >= ret) {
+    for (int i = 0; i < array_size; i++)
+    {
+        if (current_token >= ret)
+        {
             FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
             break;
         }
 
         jsmntok_t element = tokens[current_token];
 
-        if(element.type != JSMN_OBJECT) {
+        if (element.type != JSMN_OBJECT)
+        {
             FURI_LOG_E("JSMM.H", "Array element %d is not an object, skipping.", i);
             // Skip this element
             current_token += 1;
@@ -622,10 +698,12 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
         int length = element.end - element.start;
 
         // Allocate a new string for the value and copy the data
-        char* value = malloc(length + 1);
-        if(value == NULL) {
+        char *value = malloc(length + 1);
+        if (value == NULL)
+        {
             FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
-            for(int j = 0; j < actual_num_values; j++) {
+            for (int j = 0; j < actual_num_values; j++)
+            {
                 free(values[j]);
             }
             free(values);
@@ -647,14 +725,17 @@ char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, in
     *num_values = actual_num_values;
 
     // Reallocate the values array to actual_num_values if necessary
-    if(actual_num_values < array_size) {
-        char** reduced_values = realloc(values, actual_num_values * sizeof(char*));
-        if(reduced_values != NULL) {
+    if (actual_num_values < array_size)
+    {
+        char **reduced_values = realloc(values, actual_num_values * sizeof(char *));
+        if (reduced_values != NULL)
+        {
             values = reduced_values;
         }
 
         // Free the remaining values
-        for(int i = actual_num_values; i < array_size; i++) {
+        for (int i = actual_num_values; i < array_size; i++)
+        {
             free(values[i]);
         }
     }

+ 49 - 48
flip_social/jsmn/jsmn.h

@@ -19,7 +19,8 @@
 #include <stddef.h>
 
 #ifdef __cplusplus
-extern "C" {
+extern "C"
+{
 #endif
 
 #ifdef JSMN_STATIC
@@ -28,71 +29,71 @@ extern "C" {
 #define JSMN_API extern
 #endif
 
-/**
+    /**
      * JSON type identifier. Basic types are:
      * 	o Object
      * 	o Array
      * 	o String
      * 	o Other primitive: number, boolean (true/false) or null
      */
-typedef enum {
-    JSMN_UNDEFINED = 0,
-    JSMN_OBJECT = 1 << 0,
-    JSMN_ARRAY = 1 << 1,
-    JSMN_STRING = 1 << 2,
-    JSMN_PRIMITIVE = 1 << 3
-} jsmntype_t;
-
-enum jsmnerr {
-    /* Not enough tokens were provided */
-    JSMN_ERROR_NOMEM = -1,
-    /* Invalid character inside JSON string */
-    JSMN_ERROR_INVAL = -2,
-    /* The string is not a full JSON packet, more bytes expected */
-    JSMN_ERROR_PART = -3
-};
-
-/**
+    typedef enum
+    {
+        JSMN_UNDEFINED = 0,
+        JSMN_OBJECT = 1 << 0,
+        JSMN_ARRAY = 1 << 1,
+        JSMN_STRING = 1 << 2,
+        JSMN_PRIMITIVE = 1 << 3
+    } jsmntype_t;
+
+    enum jsmnerr
+    {
+        /* Not enough tokens were provided */
+        JSMN_ERROR_NOMEM = -1,
+        /* Invalid character inside JSON string */
+        JSMN_ERROR_INVAL = -2,
+        /* The string is not a full JSON packet, more bytes expected */
+        JSMN_ERROR_PART = -3
+    };
+
+    /**
      * JSON token description.
      * type		type (object, array, string etc.)
      * start	start position in JSON data string
      * end		end position in JSON data string
      */
-typedef struct {
-    jsmntype_t type;
-    int start;
-    int end;
-    int size;
+    typedef struct
+    {
+        jsmntype_t type;
+        int start;
+        int end;
+        int size;
 #ifdef JSMN_PARENT_LINKS
-    int parent;
+        int parent;
 #endif
-} jsmntok_t;
+    } jsmntok_t;
 
-/**
+    /**
      * JSON parser. Contains an array of token blocks available. Also stores
      * the string being parsed now and current position in that string.
      */
-typedef struct {
-    unsigned int pos; /* offset in the JSON string */
-    unsigned int toknext; /* next token to allocate */
-    int toksuper; /* superior token node, e.g. parent object or array */
-} jsmn_parser;
-
-/**
+    typedef struct
+    {
+        unsigned int pos;     /* offset in the JSON string */
+        unsigned int toknext; /* next token to allocate */
+        int toksuper;         /* superior token node, e.g. parent object or array */
+    } jsmn_parser;
+
+    /**
      * Create JSON parser over an array of tokens
      */
-JSMN_API void jsmn_init(jsmn_parser* parser);
+    JSMN_API void jsmn_init(jsmn_parser *parser);
 
-/**
+    /**
      * Run JSON parser. It parses a JSON data string into and array of tokens, each
      * describing a single JSON object.
      */
-JSMN_API int jsmn_parse(
-    jsmn_parser* parser,
-    const char* js,
-    const size_t len,
-    jsmntok_t* tokens,
-    const unsigned int num_tokens);
+    JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                            jsmntok_t *tokens, const unsigned int num_tokens);
 
 #ifndef JSMN_HEADER
 /* Implementation has been moved to jsmn.c */
@@ -116,16 +117,16 @@ JSMN_API int jsmn_parse(
 #include <furi.h>
 
 // Helper function to create a JSON object
-char* jsmn(const char* key, const char* value);
+char *jsmn(const char *key, const char *value);
 // Helper function to compare JSON keys
-int jsoneq(const char* json, jsmntok_t* tok, const char* s);
+int jsoneq(const char *json, jsmntok_t *tok, const char *s);
 
 // Return the value of the key in the JSON data
-char* get_json_value(char* key, char* json_data, uint32_t max_tokens);
+char *get_json_value(char *key, char *json_data, uint32_t max_tokens);
 
 // Revised get_json_array_value function
-char* get_json_array_value(char* key, uint32_t index, char* json_data, uint32_t max_tokens);
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens);
 
 // Revised get_json_array_values function with correct token skipping
-char** get_json_array_values(char* key, char* json_data, uint32_t max_tokens, int* num_values);
+char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values);
 #endif /* JB_JSMN_EDIT */

+ 191 - 169
flip_social/messages/flip_social_messages.c

@@ -1,16 +1,28 @@
 #include "flip_social_messages.h"
 
-FlipSocialModel2* flip_social_messages_alloc() {
+FlipSocialModel2 *flip_social_messages_alloc()
+{
+    if (!app_instance->submenu_messages)
+    {
+        if (!easy_flipper_set_submenu(&app_instance->submenu_messages, FlipSocialViewLoggedInMessagesSubmenu, "Messages", flip_social_callback_to_submenu_logged_in, &app_instance->view_dispatcher))
+        {
+            return NULL;
+        }
+    }
     // Allocate memory for each username only if not already allocated
-    FlipSocialModel2* users = malloc(sizeof(FlipSocialModel2));
-    if(users == NULL) {
+    FlipSocialModel2 *users = malloc(sizeof(FlipSocialModel2));
+    if (users == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for message users");
         return NULL;
     }
-    for(size_t i = 0; i < MAX_MESSAGE_USERS; i++) {
-        if(users->usernames[i] == NULL) {
+    for (size_t i = 0; i < MAX_MESSAGE_USERS; i++)
+    {
+        if (users->usernames[i] == NULL)
+        {
             users->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(users->usernames[i] == NULL) {
+            if (users->usernames[i] == NULL)
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
                 return NULL; // Return false on memory allocation failure
             }
@@ -19,24 +31,31 @@ FlipSocialModel2* flip_social_messages_alloc() {
     return users;
 }
 
-FlipSocialMessage* flip_social_user_messages_alloc() {
+FlipSocialMessage *flip_social_user_messages_alloc()
+{
     // Allocate memory for each username only if not already allocated
-    FlipSocialMessage* messages = malloc(sizeof(FlipSocialMessage));
-    if(messages == NULL) {
+    FlipSocialMessage *messages = malloc(sizeof(FlipSocialMessage));
+    if (messages == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for messages");
         return NULL;
     }
-    for(size_t i = 0; i < MAX_MESSAGE_USERS; i++) {
-        if(messages->usernames[i] == NULL) {
+    for (size_t i = 0; i < MAX_MESSAGES; i++)
+    {
+        if (messages->usernames[i] == NULL)
+        {
             messages->usernames[i] = malloc(MAX_USER_LENGTH);
-            if(messages->usernames[i] == NULL) {
+            if (messages->usernames[i] == NULL)
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
                 return NULL; // Return false on memory allocation failure
             }
         }
-        if(messages->messages[i] == NULL) {
+        if (messages->messages[i] == NULL)
+        {
             messages->messages[i] = malloc(MAX_MESSAGE_LENGTH);
-            if(messages->messages[i] == NULL) {
+            if (messages->messages[i] == NULL)
+            {
                 FURI_LOG_E(TAG, "Failed to allocate memory for message %zu", i);
                 return NULL; // Return false on memory allocation failure
             }
@@ -45,103 +64,99 @@ FlipSocialMessage* flip_social_user_messages_alloc() {
     return messages;
 }
 
-void flip_social_free_message_users() {
-    if(flip_social_message_users == NULL) {
-        FURI_LOG_E(TAG, "Message users model is NULL");
+void flip_social_free_message_users()
+{
+    if (flip_social_message_users == NULL)
+    {
         return;
     }
-    for(int i = 0; i < flip_social_message_users->count; i++) {
-        if(flip_social_message_users->usernames[i]) {
-            free(flip_social_message_users->usernames[i]);
-        }
-    }
+    free(flip_social_message_users);
+    flip_social_message_users = NULL;
 }
 
-void flip_social_free_messages() {
-    if(flip_social_messages == NULL) {
-        FURI_LOG_E(TAG, "Messages model is NULL");
-        return;
+void flip_social_free_messages()
+{
+    if (app_instance->submenu_messages)
+    {
+        submenu_free(app_instance->submenu_messages);
+        app_instance->submenu_messages = NULL;
+        view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoggedInMessagesSubmenu);
     }
-    for(int i = 0; i < flip_social_messages->count; i++) {
-        if(flip_social_messages->usernames[i]) {
-            free(flip_social_messages->usernames[i]);
-        }
-        if(flip_social_messages->messages[i]) {
-            free(flip_social_messages->messages[i]);
-        }
+    if (flip_social_messages == NULL)
+    {
+        return;
     }
+    free(flip_social_messages);
+    flip_social_messages = NULL;
 }
 
-bool flip_social_update_messages_submenu() {
-    if(app_instance->submenu_messages == NULL) {
+bool flip_social_update_messages_submenu()
+{
+    if (app_instance->submenu_messages == NULL)
+    {
         FURI_LOG_E(TAG, "Submenu is NULL");
         return false;
     }
-    if(flip_social_message_users == NULL) {
+    if (flip_social_message_users == NULL)
+    {
         FURI_LOG_E(TAG, "Message users model is NULL");
         return false;
     }
     submenu_reset(app_instance->submenu_messages);
     submenu_set_header(app_instance->submenu_messages, "Messages");
-    submenu_add_item(
-        app_instance->submenu_messages,
-        "[New Message]",
-        FlipSocialSubmenuLoggedInIndexMessagesNewMessage,
-        flip_social_callback_submenu_choices,
-        app_instance);
-    for(int i = 0; i < flip_social_message_users->count; i++) {
-        submenu_add_item(
-            app_instance->submenu_messages,
-            flip_social_message_users->usernames[i],
-            FlipSocialSubmenuLoggedInIndexMessagesUsersStart + i,
-            flip_social_callback_submenu_choices,
-            app_instance);
+    submenu_add_item(app_instance->submenu_messages, "[New Message]", FlipSocialSubmenuLoggedInIndexMessagesNewMessage, flip_social_callback_submenu_choices, app_instance);
+    for (int i = 0; i < flip_social_message_users->count; i++)
+    {
+        submenu_add_item(app_instance->submenu_messages, flip_social_message_users->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUsersStart + i, flip_social_callback_submenu_choices, app_instance);
     }
     return true;
 }
 
-bool flip_social_update_submenu_user_choices() {
-    if(app_instance->submenu_messages_user_choices == NULL) {
+bool flip_social_update_submenu_user_choices()
+{
+    if (app_instance->submenu_messages_user_choices == NULL)
+    {
         FURI_LOG_E(TAG, "Submenu is NULL");
         return false;
     }
-    if(flip_social_explore == NULL) {
+    if (flip_social_explore == NULL)
+    {
         FURI_LOG_E(TAG, "Explore model is NULL");
         return false;
     }
     submenu_reset(app_instance->submenu_messages_user_choices);
     submenu_set_header(app_instance->submenu_messages_user_choices, "Users");
-    for(int i = 0; i < flip_social_explore->count; i++) {
-        submenu_add_item(
-            app_instance->submenu_messages_user_choices,
-            flip_social_explore->usernames[i],
-            FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart + i,
-            flip_social_callback_submenu_choices,
-            app_instance);
+    for (int i = 0; i < flip_social_explore->count; i++)
+    {
+        submenu_add_item(app_instance->submenu_messages_user_choices, flip_social_explore->usernames[i], FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart + i, flip_social_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() {
-    if(app_instance->login_username_logged_out == NULL) {
+bool flip_social_get_message_users()
+{
+    if (app_instance->login_username_logged_out == NULL)
+    {
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
     char command[128];
     snprintf(
         fhttp.file_path,
         sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/message_users.txt");
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/message_users.json");
 
     fhttp.save_received_data = true;
     auth_headers_alloc();
-    snprintf(
-        command,
-        128,
-        "https://www.flipsocial.net/api/messages/%s/get/list/",
-        app_instance->login_username_logged_out);
-    if(!flipper_http_get_request_with_headers(command, auth_headers)) {
+    snprintf(command, 128, "https://www.flipsocial.net/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))
+    {
         FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
         fhttp.state = ISSUE;
         return false;
@@ -151,31 +166,35 @@ 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() {
-    if(app_instance->login_username_logged_out == NULL) {
+bool flip_social_get_messages_with_user()
+{
+    if (fhttp.state == INACTIVE)
+    {
+        FURI_LOG_E(TAG, "HTTP state is INACTIVE");
+        return false;
+    }
+    if (app_instance->login_username_logged_out == NULL)
+    {
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
-    if(!flip_social_message_users->usernames[flip_social_message_users->index] ||
-       strlen(flip_social_message_users->usernames[flip_social_message_users->index]) == 0) {
+    if (!flip_social_message_users->usernames[flip_social_message_users->index] || strlen(flip_social_message_users->usernames[flip_social_message_users->index]) == 0)
+    {
         FURI_LOG_E(TAG, "Username is NULL");
         return false;
     }
-    char command[128];
+    char command[256];
     snprintf(
         fhttp.file_path,
         sizeof(fhttp.file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages.txt");
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/%s_messages.json",
+        flip_social_message_users->usernames[flip_social_message_users->index]);
 
     fhttp.save_received_data = true;
     auth_headers_alloc();
-    snprintf(
-        command,
-        128,
-        "https://www.flipsocial.net/api/messages/%s/get/%s/",
-        app_instance->login_username_logged_out,
-        flip_social_message_users->usernames[flip_social_message_users->index]);
-    if(!flipper_http_get_request_with_headers(command, auth_headers)) {
+    snprintf(command, sizeof(command), "https://www.flipsocial.net/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))
+    {
         FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
         fhttp.state = ISSUE;
         return false;
@@ -185,15 +204,18 @@ 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() {
+bool flip_social_parse_json_message_users()
+{
     // load the received data from the saved file
-    FuriString* message_data = flipper_http_load_from_file(fhttp.file_path);
-    if(message_data == NULL) {
+    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.");
         return false;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(message_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(message_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(message_data);
         return false;
@@ -201,25 +223,21 @@ bool flip_social_parse_json_message_users() {
 
     // Allocate memory for each username only if not already allocated
     flip_social_message_users = flip_social_messages_alloc();
-    if(flip_social_message_users == NULL) {
+    if (flip_social_message_users == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for message users.");
         furi_string_free(message_data);
         free(data_cstr);
         return false;
     }
 
-    // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
-        *pos = ' ';
-    }
-
     // Initialize message users count
     flip_social_message_users->count = 0;
 
     // Extract the users array from the JSON
-    char* json_users = get_json_value("users", data_cstr, MAX_TOKENS);
-    if(json_users == NULL) {
+    char *json_users = get_json_value("users", data_cstr, 64);
+    if (json_users == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to parse users array.");
         furi_string_free(message_data);
         free(data_cstr);
@@ -227,37 +245,35 @@ bool flip_social_parse_json_message_users() {
     }
 
     // Manual tokenization for comma-separated values
-    char* start = json_users + 1; // Skip the opening bracket
-    char* end;
-    while((end = strchr(start, ',')) != NULL &&
-          flip_social_message_users->count < MAX_MESSAGE_USERS) {
+    char *start = json_users + 1; // Skip the opening bracket
+    char *end;
+    while ((end = strchr(start, ',')) != NULL && flip_social_message_users->count < MAX_MESSAGE_USERS)
+    {
         *end = '\0'; // Null-terminate the current token
 
         // Remove quotes
-        if(*start == '"') start++;
-        if(*(end - 1) == '"') *(end - 1) = '\0';
+        if (*start == '"')
+            start++;
+        if (*(end - 1) == '"')
+            *(end - 1) = '\0';
 
         // Copy username to pre-allocated memory
-        snprintf(
-            flip_social_message_users->usernames[flip_social_message_users->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+        snprintf(flip_social_message_users->usernames[flip_social_message_users->count], MAX_USER_LENGTH, "%s", start);
         flip_social_message_users->count++;
         start = end + 1;
     }
 
     // Handle the last token
-    if(*start != '\0' && flip_social_message_users->count < MAX_MESSAGE_USERS) {
-        if(*start == '"') start++;
-        if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
-        if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
-
-        snprintf(
-            flip_social_message_users->usernames[flip_social_message_users->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+    if (*start != '\0' && flip_social_message_users->count < MAX_MESSAGE_USERS)
+    {
+        if (*start == '"')
+            start++;
+        if (*(start + strlen(start) - 1) == ']')
+            *(start + strlen(start) - 1) = '\0';
+        if (*(start + strlen(start) - 1) == '"')
+            *(start + strlen(start) - 1) = '\0';
+
+        snprintf(flip_social_message_users->usernames[flip_social_message_users->count], MAX_USER_LENGTH, "%s", start);
         flip_social_message_users->count++;
     }
 
@@ -274,15 +290,18 @@ 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 flip_social_parse_json_message_user_choices()
+{
     // load the received data from the saved file
-    FuriString* user_data = flipper_http_load_from_file(fhttp.file_path);
-    if(user_data == NULL) {
+    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.");
         return false;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(user_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(user_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(user_data);
         return false;
@@ -290,25 +309,21 @@ bool flip_social_parse_json_message_user_choices() {
 
     // Allocate memory for each username only if not already allocated
     flip_social_explore = flip_social_explore_alloc();
-    if(flip_social_explore == NULL) {
+    if (flip_social_explore == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for explore usernames.");
         furi_string_free(user_data);
         free(data_cstr);
         return false;
     }
 
-    // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
-        *pos = ' ';
-    }
-
     // Initialize explore count
     flip_social_explore->count = 0;
 
     // Extract the users array from the JSON
-    char* json_users = get_json_value("users", data_cstr, MAX_TOKENS);
-    if(json_users == NULL) {
+    char *json_users = get_json_value("users", data_cstr, 64);
+    if (json_users == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to parse users array.");
         furi_string_free(user_data);
         free(data_cstr);
@@ -316,36 +331,35 @@ bool flip_social_parse_json_message_user_choices() {
     }
 
     // Manual tokenization for comma-separated values
-    char* start = json_users + 1; // Skip the opening bracket
-    char* end;
-    while((end = strchr(start, ',')) != NULL && flip_social_explore->count < MAX_EXPLORE_USERS) {
+    char *start = json_users + 1; // Skip the opening bracket
+    char *end;
+    while ((end = strchr(start, ',')) != NULL && flip_social_explore->count < MAX_EXPLORE_USERS)
+    {
         *end = '\0'; // Null-terminate the current token
 
         // Remove quotes
-        if(*start == '"') start++;
-        if(*(end - 1) == '"') *(end - 1) = '\0';
+        if (*start == '"')
+            start++;
+        if (*(end - 1) == '"')
+            *(end - 1) = '\0';
 
         // Copy username to pre-allocated memory
-        snprintf(
-            flip_social_explore->usernames[flip_social_explore->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+        snprintf(flip_social_explore->usernames[flip_social_explore->count], MAX_USER_LENGTH, "%s", start);
         flip_social_explore->count++;
         start = end + 1;
     }
 
     // Handle the last token
-    if(*start != '\0' && flip_social_explore->count < MAX_EXPLORE_USERS) {
-        if(*start == '"') start++;
-        if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
-        if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
-
-        snprintf(
-            flip_social_explore->usernames[flip_social_explore->count],
-            MAX_USER_LENGTH,
-            "%s",
-            start);
+    if (*start != '\0' && flip_social_explore->count < MAX_EXPLORE_USERS)
+    {
+        if (*start == '"')
+            start++;
+        if (*(start + strlen(start) - 1) == ']')
+            *(start + strlen(start) - 1) = '\0';
+        if (*(start + strlen(start) - 1) == '"')
+            *(start + strlen(start) - 1) = '\0';
+
+        snprintf(flip_social_explore->usernames[flip_social_explore->count], MAX_USER_LENGTH, "%s", start);
         flip_social_explore->count++;
     }
 
@@ -362,15 +376,18 @@ 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 flip_social_parse_json_messages()
+{
     // load the received data from the saved file
-    FuriString* message_data = flipper_http_load_from_file(fhttp.file_path);
-    if(message_data == NULL) {
+    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.");
         return false;
     }
-    char* data_cstr = (char*)furi_string_get_cstr(message_data);
-    if(data_cstr == NULL) {
+    char *data_cstr = (char *)furi_string_get_cstr(message_data);
+    if (data_cstr == NULL)
+    {
         FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
         furi_string_free(message_data);
         return false;
@@ -378,35 +395,33 @@ bool flip_social_parse_json_messages() {
 
     // Allocate memory for each message only if not already allocated
     flip_social_messages = flip_social_user_messages_alloc();
-    if(!flip_social_messages) {
+    if (!flip_social_messages)
+    {
         FURI_LOG_E(TAG, "Failed to allocate memory for messages.");
         furi_string_free(message_data);
         free(data_cstr);
         return false;
     }
 
-    // Remove newlines
-    char* pos = data_cstr;
-    while((pos = strchr(pos, '\n')) != NULL) {
-        *pos = ' ';
-    }
-
     // Initialize messages count
     flip_social_messages->count = 0;
 
     // Iterate through the messages array
-    for(int i = 0; i < MAX_MESSAGES; i++) {
+    for (int i = 0; i < MAX_MESSAGES; i++)
+    {
         // Parse each item in the array
-        char* item = get_json_array_value("conversations", i, data_cstr, MAX_TOKENS);
-        if(item == NULL) {
+        char *item = get_json_array_value("conversations", i, data_cstr, 64);
+        if (item == NULL)
+        {
             break;
         }
 
         // Extract individual fields from the JSON object
-        char* sender = get_json_value("sender", item, MAX_TOKENS);
-        char* content = get_json_value("content", item, MAX_TOKENS);
+        char *sender = get_json_value("sender", item, 8);
+        char *content = get_json_value("content", item, 8);
 
-        if(sender == NULL || content == NULL) {
+        if (sender == NULL || content == NULL)
+        {
             FURI_LOG_E(TAG, "Failed to parse item fields.");
             free(item);
             continue;
@@ -421,7 +436,14 @@ bool flip_social_parse_json_messages() {
         free(sender);
         free(content);
     }
+    if (!messages_dialog_alloc(true))
+    {
+        FURI_LOG_E(TAG, "Failed to allocate and set messages dialog.");
+        furi_string_free(message_data);
+        free(data_cstr);
+        return false;
+    }
     furi_string_free(message_data);
     free(data_cstr);
     return true;
-}
+}

+ 3 - 3
flip_social/messages/flip_social_messages.h

@@ -5,8 +5,8 @@
 #include <callback/flip_social_callback.h>
 #include <explore/flip_social_explore.h>
 
-FlipSocialModel2* flip_social_messages_alloc();
-FlipSocialMessage* flip_social_user_messages_alloc();
+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();
@@ -24,4 +24,4 @@ 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
+#endif

+ 162 - 0
flip_social/text_input/rpc_keyboard.h

@@ -0,0 +1,162 @@
+#pragma once
+
+#include <core/common_defines.h>
+#include <core/mutex.h>
+#include <core/pubsub.h>
+
+#define RECORD_RPC_KEYBOARD "rpckeyboard"
+
+#define RPC_KEYBOARD_KEY_RIGHT '\x13'
+#define RPC_KEYBOARD_KEY_LEFT '\x14'
+#define RPC_KEYBOARD_KEY_ENTER '\x0D'
+#define RPC_KEYBOARD_KEY_BACKSPACE '\x08'
+
+typedef enum
+{
+    // Unknown error occurred
+    RpcKeyboardChatpadStatusError,
+    // The chatpad worker is stopped
+    RpcKeyboardChatpadStatusStopped,
+    // The chatpad worker is started, but not ready
+    RpcKeyboardChatpadStatusStarted,
+    // The chatpad worker is ready and got response from chatpad
+    RpcKeyboardChatpadStatusReady,
+} RpcKeyboardChatpadStatus;
+
+typedef struct RpcKeyboard RpcKeyboard;
+
+typedef enum
+{
+    // Replacement text was provided by the user
+    RpcKeyboardEventTypeTextEntered,
+    // A single character was provided by the user
+    RpcKeyboardEventTypeCharEntered,
+    // A macro was entered by the user
+    RpcKeyboardEventTypeMacroEntered,
+} RpcKeyboardEventType;
+
+typedef struct
+{
+    // The mutex to protect the data, call furi_mutex_acquire/furi_mutex_release.
+    FuriMutex *mutex;
+    // The text message, macro or character.
+    char message[256];
+    // The length of the message.
+    uint16_t length;
+    // The newline enabled flag, allow newline to submit text.
+    bool newline_enabled;
+} RpcKeyboardEventData;
+
+typedef struct
+{
+    RpcKeyboardEventType type;
+    RpcKeyboardEventData data;
+} RpcKeyboardEvent;
+
+typedef FuriPubSub *(*RpcKeyboardGetPubsub)(RpcKeyboard *rpc_keyboard);
+typedef void (*RpcKeyboardNewlineEnable)(RpcKeyboard *rpc_keyboard, bool enable);
+typedef void (*RpcKeyboardPublishCharFn)(RpcKeyboard *keyboard, char character);
+typedef void (*RpcKeyboardPublishMacroFn)(RpcKeyboard *rpc_keyboard, char macro);
+typedef char *(*RpcKeyboardGetMacroFn)(RpcKeyboard *rpc_keyboard, char macro);
+typedef void (*RpcKeyboardSetMacroFn)(RpcKeyboard *rpc_keyboard, char macro, char *value);
+typedef void (*RpcKeyboardChatpadStartFn)(RpcKeyboard *rpc_keyboard);
+typedef void (*RpcKeyboardChatpadStopFn)(RpcKeyboard *rpc_keyboard);
+typedef RpcKeyboardChatpadStatus (*RpcKeyboardChatpadStatusFn)(RpcKeyboard *rpc_keyboard);
+
+typedef struct RpcKeyboardFunctions RpcKeyboardFunctions;
+struct RpcKeyboardFunctions
+{
+    uint16_t major;
+    uint16_t minor;
+    RpcKeyboardGetPubsub fn_get_pubsub;
+    RpcKeyboardNewlineEnable fn_newline_enable;
+    RpcKeyboardPublishCharFn fn_publish_char;
+    RpcKeyboardPublishMacroFn fn_publish_macro;
+    RpcKeyboardGetMacroFn fn_get_macro;
+    RpcKeyboardSetMacroFn fn_set_macro;
+    RpcKeyboardChatpadStartFn fn_chatpad_start;
+    RpcKeyboardChatpadStopFn fn_chatpad_stop;
+    RpcKeyboardChatpadStatusFn fn_chatpad_status;
+};
+
+/**
+ * @brief STARTUP - Register the remote keyboard.
+ */
+void rpc_keyboard_register(void);
+
+/**
+ * @brief UNUSED - Unregister the remote keyboard.
+ */
+void rpc_keyboard_release(void);
+
+/**
+ * @brief Get the pubsub object for the remote keyboard.
+ * @details This function returns the pubsub object, use to subscribe to keyboard events.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @return FuriPubSub* pointer to the pubsub object.
+ */
+FuriPubSub *rpc_keyboard_get_pubsub(RpcKeyboard *rpc_keyboard);
+
+/**
+ * @brief Enable or disable newline character submitting the text.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] enable true to enable, false to disable.
+ */
+void rpc_keyboard_newline_enable(RpcKeyboard *rpc_keyboard, bool enable);
+
+/**
+ * @brief Publish the replacement text to the remote keyboard.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] bytes pointer to the text buffer.
+ * @param[in] buffer_size size of the text buffer.
+ */
+void rpc_keyboard_publish_text(RpcKeyboard *rpc_keyboard, uint8_t *bytes, uint32_t buffer_size);
+
+/**
+ * @brief Publish a single key pressed on the remote keyboard.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] character the character that was pressed.
+ */
+void rpc_keyboard_publish_char(RpcKeyboard *rpc_keyboard, char character);
+
+/**
+ * @brief Publish a macro key pressed on the remote keyboard.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] character the macro key that was pressed.
+ */
+void rpc_keyboard_publish_macro(RpcKeyboard *rpc_keyboard, char macro);
+
+/**
+ * @brief Get the macro text associated with a macro key.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] macro the macro key.
+ * @return char* pointer to the macro text. NULL if the macro key is not set. User must free the memory.
+ */
+char *rpc_keyboard_get_macro(RpcKeyboard *rpc_keyboard, char macro);
+
+/**
+ * @brief Set the macro text associated with a macro key.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] macro the macro key.
+ * @param[in] value the macro text.
+ */
+void rpc_keyboard_set_macro(RpcKeyboard *rpc_keyboard, char macro, char *value);
+
+/**
+ * @brief Initializes the chatpad and starts listening for keypresses.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ */
+void rpc_keyboard_chatpad_start(RpcKeyboard *rpc_keyboard);
+
+/**
+ * @brief Stops the chatpad & frees resources.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ */
+void rpc_keyboard_chatpad_stop(RpcKeyboard *rpc_keyboard);
+
+/**
+ * @brief Get the status of the chatpad.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @return RpcKeyboardChatpadStatus the status of the chatpad.
+ */
+RpcKeyboardChatpadStatus rpc_keyboard_chatpad_status(RpcKeyboard *rpc_keyboard);

+ 150 - 0
flip_social/text_input/rpc_keyboard_stub.c

@@ -0,0 +1,150 @@
+#include "rpc_keyboard.h"
+
+#include <furi.h>
+
+static bool rpc_keyboard_functions_check_version(RpcKeyboardFunctions *stub)
+{
+    furi_check(stub);
+    if (stub->major == 1 && stub->minor > 2)
+    {
+        return true;
+    }
+    FURI_LOG_D("RpcKeyboard", "Unsupported version %d.%d", stub->major, stub->minor);
+    return false;
+}
+
+/**
+ * @brief Get the pubsub object for the remote keyboard.
+ * @details This function returns the pubsub object, use to subscribe to keyboard events.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @return FuriPubSub* pointer to the pubsub object.
+ */
+FuriPubSub *rpc_keyboard_get_pubsub(RpcKeyboard *rpc_keyboard)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return NULL;
+    }
+    return stub->fn_get_pubsub((RpcKeyboard *)rpc_keyboard);
+}
+
+/**
+ * @brief Enable or disable newline character submitting the text.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] enable true to enable, false to disable.
+ */
+void rpc_keyboard_newline_enable(RpcKeyboard *rpc_keyboard, bool enable)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_newline_enable((RpcKeyboard *)rpc_keyboard, enable);
+}
+
+/**
+ * @brief Publish a single key pressed on the remote keyboard.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] character the character that was pressed.
+ */
+void rpc_keyboard_publish_char(RpcKeyboard *rpc_keyboard, char character)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_publish_char((RpcKeyboard *)rpc_keyboard, character);
+}
+
+/**
+ * @brief Publish a macro key pressed on the remote keyboard.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] character the macro key that was pressed.
+ */
+void rpc_keyboard_publish_macro(RpcKeyboard *rpc_keyboard, char macro)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_publish_macro((RpcKeyboard *)rpc_keyboard, macro);
+}
+
+/**
+ * @brief Get the macro text associated with a macro key.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] macro the macro key.
+ * @return char* pointer to the macro text. NULL if the macro key is not set. User must free the memory.
+ */
+char *rpc_keyboard_get_macro(RpcKeyboard *rpc_keyboard, char macro)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return NULL;
+    }
+    return stub->fn_get_macro((RpcKeyboard *)rpc_keyboard, macro);
+}
+
+/**
+ * @brief Set the macro text associated with a macro key.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @param[in] macro the macro key.
+ * @param[in] value the macro text.
+ */
+void rpc_keyboard_set_macro(RpcKeyboard *rpc_keyboard, char macro, char *value)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_set_macro((RpcKeyboard *)rpc_keyboard, macro, value);
+}
+
+/**
+ * @brief Initializes the chatpad and starts listening for keypresses.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ */
+void rpc_keyboard_chatpad_start(RpcKeyboard *rpc_keyboard)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_chatpad_start((RpcKeyboard *)rpc_keyboard);
+}
+
+/**
+ * @brief Stops the chatpad & frees resources.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ */
+void rpc_keyboard_chatpad_stop(RpcKeyboard *rpc_keyboard)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return;
+    }
+    stub->fn_chatpad_stop((RpcKeyboard *)rpc_keyboard);
+}
+
+/**
+ * @brief Get the status of the chatpad.
+ * @param[in] rpc_keyboard pointer to the RECORD_RPC_KEYBOARD.
+ * @return RpcKeyboardChatpadStatus the status of the chatpad.
+ */
+RpcKeyboardChatpadStatus rpc_keyboard_chatpad_status(RpcKeyboard *rpc_keyboard)
+{
+    RpcKeyboardFunctions *stub = (RpcKeyboardFunctions *)rpc_keyboard;
+    if (!rpc_keyboard_functions_check_version(stub))
+    {
+        return RpcKeyboardChatpadStatusError;
+    }
+    return stub->fn_chatpad_status((RpcKeyboard *)rpc_keyboard);
+}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio