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

Add home notification/announcements

- if the user is logged in and the board is connected, it will fetch the latest announcement and notification if there is new data
jblanked 1 год назад
Родитель
Сommit
1d8311971f

+ 24 - 1
app.c

@@ -22,6 +22,7 @@ int32_t main_flip_social(void *p)
     }
 
     // check if board is connected (Derek Jamison)
+    uint8_t counter = 10;
     // initialize the http
     if (flipper_http_init(flipper_http_rx_callback, app_instance))
     {
@@ -34,7 +35,6 @@ int32_t main_flip_social(void *p)
         }
 
         // Try to wait for pong response.
-        uint8_t counter = 10;
         while (fhttp.state == INACTIVE && --counter > 0)
         {
             FURI_LOG_D(TAG, "Waiting for PONG");
@@ -42,7 +42,13 @@ int32_t main_flip_social(void *p)
         }
 
         if (counter == 0)
+        {
             easy_flipper_dialog("FlipperHTTP Error", "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.");
+        }
+        else
+        {
+            save_char("is_connected", "true");
+        }
 
         flipper_http_deinit();
     }
@@ -51,6 +57,23 @@ int32_t main_flip_social(void *p)
         easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
     }
 
+    // if counter is not 0, check notifications
+    if (counter != 0)
+    {
+        char is_connected[5];
+        char is_logged_in[5];
+        load_char("is_connected", is_connected, 5);
+        load_char("is_logged_in", is_logged_in, 5);
+
+        if (strcmp(is_connected, "true") == 0)
+        {
+            if (strcmp(is_logged_in, "true") == 0)
+            {
+                flip_social_home_notification();
+            }
+        }
+    }
+
     // Run the view dispatcher
     view_dispatcher_run(app_instance->view_dispatcher);
 

+ 5 - 0
assets/CHANGELOG.md

@@ -1,6 +1,11 @@
 ## 1.0 - Official Release
 - Final memory improvements
 - Updated the New Message option in the Messages view to allow the user to search for users to send a message to.
+- Updated the display of the Feed to use a custom view and custom font, and show how long ago the post was created
+- Organized the files saved/utilized in the apps_data folder
+- Fixed bugs in the Direct Messaging View
+- Fixed bugs in the Pre-Save View
+- Added home announcements and notifications.
 
 ## 0.8 - New Features
 - Added support for RPC_KEYBOARD (thanks to Derek Jamison).

+ 143 - 0
callback/flip_social_callback.c

@@ -2557,3 +2557,146 @@ void flip_social_generic_switch_to_view(FlipSocialApp *app, char *title, DataLoa
 
     view_dispatcher_switch_to_view(app->view_dispatcher, view_id);
 }
+
+static bool flip_social_get_home_notification()
+{
+    if (!app_instance)
+    {
+        FURI_LOG_E(TAG, "app_instance is NULL");
+        return false;
+    }
+    if (!flipper_http_init(flipper_http_rx_callback, app_instance))
+    {
+        FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
+        return false;
+    }
+    // Create the directory for saving settings
+    char directory_path[256];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/data");
+
+    // Create the directory
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, directory_path);
+    furi_record_close(RECORD_STORAGE);
+    auth_headers_alloc();
+    snprintf(
+        fhttp.file_path,
+        sizeof(fhttp.file_path),
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/data/notification.json");
+
+    fhttp.save_received_data = true;
+    return flipper_http_get_request_with_headers("https://www.flipsocial.net/api/flip-social-notifications/", auth_headers);
+}
+static bool flip_social_parse_home_notification()
+{
+    FuriString *notification = flipper_http_load_from_file(fhttp.file_path);
+    if (notification == NULL)
+    {
+        FURI_LOG_E(TAG, "Failed to load notification from file");
+        flipper_http_deinit();
+        return false;
+    }
+    flipper_http_deinit();
+    // check if announcement and analytics key exists
+    FuriString *announcement_json = get_json_value_furi("announcement", notification);
+    FuriString *analytics_json = get_json_value_furi("analytics", notification);
+    if (announcement_json == NULL || analytics_json == NULL)
+    {
+        FURI_LOG_E(TAG, "Failed to get announcement or analytics from notification");
+        if (announcement_json)
+        {
+            furi_string_free(announcement_json);
+        }
+        if (analytics_json)
+        {
+            furi_string_free(analytics_json);
+        }
+        return false;
+    }
+    FuriString *announcement_value = get_json_value_furi("content", announcement_json);
+    FuriString *announcement_time = get_json_value_furi("date_created", announcement_json);
+    FuriString *analytics_value = get_json_value_furi("count", analytics_json);
+    FuriString *analytics_time = get_json_value_furi("time", analytics_json);
+    if (!announcement_value || !announcement_time || !analytics_value || !analytics_time)
+    {
+        FURI_LOG_E(TAG, "Failed to get announcement or analytics value from notification");
+        if (announcement_value)
+        {
+            furi_string_free(announcement_value);
+        }
+        if (announcement_time)
+        {
+            furi_string_free(announcement_time);
+        }
+        if (analytics_value)
+        {
+            furi_string_free(analytics_value);
+        }
+        if (analytics_time)
+        {
+            furi_string_free(analytics_time);
+        }
+        return false;
+    }
+    // load previous announcement and analytics times to see if there is a new announcement or analytics
+    char past_analytics_time[32];
+    char past_announcement_time[32];
+    if (load_char("analytics_time", past_analytics_time, sizeof(past_analytics_time)) && load_char("announcement_time", past_announcement_time, sizeof(past_announcement_time)))
+    {
+        // check if the announcement or analytics time has changed
+        if (strcmp(furi_string_get_cstr(announcement_time), past_announcement_time) == 0 && strcmp(furi_string_get_cstr(analytics_time), past_analytics_time) == 0)
+        {
+            FURI_LOG_D(TAG, "No new announcement or analytics");
+            furi_string_free(announcement_value);
+            furi_string_free(announcement_time);
+            furi_string_free(analytics_value);
+            furi_string_free(analytics_time);
+            furi_string_free(announcement_json);
+            furi_string_free(analytics_json);
+            furi_string_free(notification);
+            return true;
+        }
+    }
+    // save the new announcement and analytics time
+    save_char("analytics_time", furi_string_get_cstr(analytics_time));
+    save_char("announcement_time", furi_string_get_cstr(announcement_time));
+    // show the announcement and analytics
+    char analytics_text[128];
+    // if previous analytics posts is not empty, then subtract the current posts from the previous psots and add it to analytics_text
+    if (atoi(furi_string_get_cstr(analytics_value)) > 0)
+    {
+        char past_analytics_value[32];
+        if (load_char("analytics_value", past_analytics_value, sizeof(past_analytics_value)))
+        {
+            int past_posts = atoi(past_analytics_value);
+            int current_posts = atoi(furi_string_get_cstr(analytics_value));
+            int new_posts = current_posts - past_posts;
+            snprintf(analytics_text, sizeof(analytics_text), "%s feed posts\n%d new posts", furi_string_get_cstr(analytics_value), new_posts);
+        }
+        else
+        {
+            snprintf(analytics_text, sizeof(analytics_text), "%s feed posts", furi_string_get_cstr(analytics_value));
+        }
+        save_char("analytics_value", furi_string_get_cstr(analytics_value));
+    }
+    else
+    {
+        snprintf(analytics_text, sizeof(analytics_text), "%s feed posts", furi_string_get_cstr(analytics_value));
+    }
+    easy_flipper_dialog("Announcement", (char *)furi_string_get_cstr(announcement_value));
+    easy_flipper_dialog("Analytics", analytics_text);
+    furi_string_free(announcement_value);
+    furi_string_free(announcement_time);
+    furi_string_free(analytics_value);
+    furi_string_free(analytics_time);
+    furi_string_free(announcement_json);
+    furi_string_free(analytics_json);
+    furi_string_free(notification);
+    return true;
+}
+
+// home notification
+bool flip_social_home_notification()
+{
+    return flipper_http_process_response_async(flip_social_get_home_notification, flip_social_parse_home_notification);
+}

+ 2 - 0
callback/flip_social_callback.h

@@ -301,4 +301,6 @@ void flip_social_loader_free_model(View *view);
 bool flip_social_custom_event_callback(void *context, uint32_t index);
 void messages_dialog_callback(DialogExResult result, void *context);
 void feed_dialog_callback(DialogExResult result, void *context);
+//
+bool flip_social_home_notification();
 #endif

+ 1 - 3
feed/flip_social_feed.c

@@ -26,7 +26,7 @@ bool flip_social_get_feed(bool alloc_http)
     fhttp.save_received_data = true;
     auth_headers_alloc();
     char command[96];
-    snprintf(command, 96, "https://www.flipsocial.net/api/feed/20/%s/max/", app_instance->login_username_logged_out);
+    snprintf(command, 96, "https://www.flipsocial.net/api/feed/%d/%s/max/", MAX_FEED_ITEMS, 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");
@@ -70,7 +70,6 @@ FlipSocialFeedMini *flip_social_parse_json_feed()
 
         // Extract individual fields from the JSON object
         FuriString *id = get_json_value_furi("id", item);
-
         if (id == NULL)
         {
             FURI_LOG_E(TAG, "Failed to parse item fields.");
@@ -78,7 +77,6 @@ FlipSocialFeedMini *flip_social_parse_json_feed()
             furi_string_free(id);
             continue;
         }
-
         if (!flip_social_save_post(furi_string_get_cstr(id), furi_string_get_cstr(item)))
         {
             FURI_LOG_E(TAG, "Failed to save post.");

+ 1 - 2
flip_social.h

@@ -17,7 +17,7 @@
 #define MAX_EXPLORE_USERS 50      // Maximum number of users to explore
 #define MAX_USER_LENGTH 32        // Maximum length of a username
 #define MAX_FRIENDS 50            // Maximum number of friends
-#define MAX_FEED_ITEMS 50         // Maximum number of feed items
+#define MAX_FEED_ITEMS 30         // Maximum number of feed items
 #define MAX_LINE_LENGTH 27
 #define MAX_MESSAGE_USERS 40 // Maximum number of users to display in the submenu
 #define MAX_MESSAGES 20      // Maximum number of meesages between each user
@@ -289,7 +289,6 @@ typedef struct
     DialogEx *dialog_friends;
     DialogEx *dialog_messages;
     DialogEx *dialog_compose;
-    DialogEx *dialog_feed;
 
     View *view_feed;
 

+ 91 - 0
flip_storage/flip_social_storage.c

@@ -410,5 +410,96 @@ bool flip_social_save_post(const char *post_id, const char *json_feed_data)
     storage_file_close(file);
     storage_file_free(file);
     furi_record_close(RECORD_STORAGE);
+    return true;
+}
+//
+bool save_char(
+    const char *path_name, const char *value)
+{
+    if (!value)
+    {
+        return false;
+    }
+    // Create the directory for saving settings
+    char directory_path[256];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/data");
+
+    // Create the directory
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, directory_path);
+
+    // Open the settings file
+    File *file = storage_file_alloc(storage);
+    char file_path[256];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/data/%s.txt", path_name);
+
+    // Open the file in write mode
+    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to open file for writing: %s", file_path);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Write the data to the file
+    size_t data_size = strlen(value) + 1; // Include null terminator
+    if (storage_file_write(file, value, data_size) != data_size)
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
+    return true;
+}
+
+bool load_char(
+    const char *path_name,
+    char *value,
+    size_t value_size)
+{
+    if (!value)
+    {
+        return false;
+    }
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    File *file = storage_file_alloc(storage);
+
+    char file_path[256];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/data/%s.txt", path_name);
+
+    // Open the file for reading
+    if (!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING))
+    {
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return NULL; // Return false if the file does not exist
+    }
+
+    // Read data into the buffer
+    size_t read_count = storage_file_read(file, value, value_size);
+    if (storage_file_get_error(file) != FSE_OK)
+    {
+        FURI_LOG_E(HTTP_TAG, "Error reading from file.");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Ensure null-termination
+    value[read_count - 1] = '\0';
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
     return true;
 }

+ 8 - 0
flip_storage/flip_social_storage.h

@@ -38,4 +38,12 @@ bool load_settings(
     size_t is_logged_in_size);
 
 bool flip_social_save_post(const char *post_id, const char *json_feed_data);
+//
+
+bool save_char(
+    const char *path_name, const char *value);
+bool load_char(
+    const char *path_name,
+    char *value,
+    size_t value_size);
 #endif