|
|
@@ -1,6 +1,7 @@
|
|
|
#include <alloc/alloc.h>
|
|
|
#include <flip_storage/flip_social_storage.h>
|
|
|
#include <feed/feed.h>
|
|
|
+#include <callback/callback.h>
|
|
|
|
|
|
FlipSocialApp *alloc_flip_social_app()
|
|
|
{
|
|
|
@@ -381,6 +382,9 @@ FlipSocialApp *alloc_flip_social_app()
|
|
|
view_dispatcher_switch_to_view(app->view_dispatcher, FlipSocialViewLoggedOutSubmenu);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ app->empty_screen = empty_screen_alloc();
|
|
|
+ view_dispatcher_add_view(app->view_dispatcher, FlipSocialViewEmpty, empty_screen_get_view(app->empty_screen));
|
|
|
return app;
|
|
|
}
|
|
|
|
|
|
@@ -629,330 +633,6 @@ void on_input(const void *event, void *ctx)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Make sure to define a suitable MAX_LINE_LENGTH
|
|
|
-// For example:
|
|
|
-
|
|
|
-#define MAX_LINES 6
|
|
|
-#define LINE_HEIGHT 8
|
|
|
-#define MAX_LINE_WIDTH_PX 128
|
|
|
-#define TEMP_BUF_SIZE 128
|
|
|
-
|
|
|
-static void draw_user_message(Canvas *canvas, const char *user_message, int x, int y)
|
|
|
-{
|
|
|
- if (!user_message)
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "User message is NULL.");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // We will read through user_message and extract words manually
|
|
|
- const char *p = user_message;
|
|
|
-
|
|
|
- // Skip leading spaces
|
|
|
- while (*p == ' ')
|
|
|
- p++;
|
|
|
-
|
|
|
- char line[TEMP_BUF_SIZE];
|
|
|
- size_t line_len = 0;
|
|
|
- line[0] = '\0';
|
|
|
- int line_num = 0;
|
|
|
-
|
|
|
- while (*p && line_num < MAX_LINES)
|
|
|
- {
|
|
|
- // Find the end of the next word
|
|
|
- const char *word_start = p;
|
|
|
- while (*p && *p != ' ')
|
|
|
- p++;
|
|
|
- size_t word_len = p - word_start;
|
|
|
-
|
|
|
- // Extract the word into a temporary buffer
|
|
|
- char word[TEMP_BUF_SIZE];
|
|
|
- if (word_len > TEMP_BUF_SIZE - 1)
|
|
|
- {
|
|
|
- word_len = TEMP_BUF_SIZE - 1; // Just to avoid overflow if extremely large
|
|
|
- }
|
|
|
- memcpy(word, word_start, word_len);
|
|
|
- word[word_len] = '\0';
|
|
|
-
|
|
|
- // Skip trailing spaces for the next iteration
|
|
|
- while (*p == ' ')
|
|
|
- p++;
|
|
|
-
|
|
|
- if (word_len == 0)
|
|
|
- {
|
|
|
- // Empty word (consecutive spaces?), just continue
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // Check how the word fits into the current line
|
|
|
- char test_line[TEMP_BUF_SIZE + 128];
|
|
|
- if (line_len == 0)
|
|
|
- {
|
|
|
- // If line is empty, the line would just be this word
|
|
|
- strncpy(test_line, word, sizeof(test_line) - 1);
|
|
|
- test_line[sizeof(test_line) - 1] = '\0';
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // If not empty, we add a space and then the word
|
|
|
- snprintf(test_line, sizeof(test_line), "%s %s", line, word);
|
|
|
- }
|
|
|
-
|
|
|
- uint16_t width = canvas_string_width(canvas, test_line);
|
|
|
- if (width <= MAX_LINE_WIDTH_PX)
|
|
|
- {
|
|
|
- // The word fits on this line
|
|
|
- strcpy(line, test_line);
|
|
|
- line_len = strlen(line);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // The word doesn't fit on this line
|
|
|
- // First, draw the current line if it's not empty
|
|
|
- if (line_len > 0)
|
|
|
- {
|
|
|
- canvas_draw_str_aligned(canvas, x, y + line_num * LINE_HEIGHT, AlignLeft, AlignTop, line);
|
|
|
- line_num++;
|
|
|
- if (line_num >= MAX_LINES)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // Now we try to put the current word on a new line
|
|
|
- // Check if the word itself fits on an empty line
|
|
|
- width = canvas_string_width(canvas, word);
|
|
|
- if (width <= MAX_LINE_WIDTH_PX)
|
|
|
- {
|
|
|
- // The whole word fits on a new line
|
|
|
- strcpy(line, word);
|
|
|
- line_len = word_len;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // The word alone doesn't fit. We must truncate it.
|
|
|
- // We'll find the largest substring of the word that fits.
|
|
|
- size_t truncate_len = word_len;
|
|
|
- while (truncate_len > 0)
|
|
|
- {
|
|
|
- char truncated[TEMP_BUF_SIZE];
|
|
|
- strncpy(truncated, word, truncate_len);
|
|
|
- truncated[truncate_len] = '\0';
|
|
|
- if (canvas_string_width(canvas, truncated) <= MAX_LINE_WIDTH_PX)
|
|
|
- {
|
|
|
- // Found a substring that fits
|
|
|
- strcpy(line, truncated);
|
|
|
- line_len = truncate_len;
|
|
|
- break;
|
|
|
- }
|
|
|
- truncate_len--;
|
|
|
- }
|
|
|
-
|
|
|
- if (line_len == 0)
|
|
|
- {
|
|
|
- // Could not fit a single character. Skip this word.
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Draw any remaining text in the buffer if we have lines left
|
|
|
- if (line_len > 0 && line_num < MAX_LINES)
|
|
|
- {
|
|
|
- canvas_draw_str_aligned(canvas, x, y + line_num * LINE_HEIGHT, AlignLeft, AlignTop, line);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void flip_social_feed_draw_callback(Canvas *canvas, void *model)
|
|
|
-{
|
|
|
- UNUSED(model);
|
|
|
- canvas_clear(canvas);
|
|
|
- canvas_set_font_custom(canvas, FONT_SIZE_LARGE);
|
|
|
- canvas_draw_str(canvas, 0, 7, flip_feed_item->username);
|
|
|
- canvas_set_font_custom(canvas, FONT_SIZE_MEDIUM);
|
|
|
- draw_user_message(canvas, flip_feed_item->message, 0, 12);
|
|
|
- canvas_set_font_custom(canvas, FONT_SIZE_SMALL);
|
|
|
- char flip_message[32];
|
|
|
- snprintf(flip_message, sizeof(flip_message), "%u %s", flip_feed_item->flips, flip_feed_item->flips == 1 ? "flip" : "flips");
|
|
|
- canvas_draw_str(canvas, 0, 60, flip_message); // Draw the number of flips
|
|
|
- char flip_status[16];
|
|
|
- snprintf(flip_status, sizeof(flip_status), flip_feed_item->is_flipped ? "Unflip" : "Flip");
|
|
|
- canvas_draw_str(canvas, 32, 60, flip_status); // Draw the flip status
|
|
|
- canvas_draw_str(canvas, 64, 60, flip_feed_item->date_created); // Draw the date
|
|
|
-}
|
|
|
-
|
|
|
-static bool flip_social_feed_input_callback(InputEvent *event, void *context)
|
|
|
-{
|
|
|
- UNUSED(context);
|
|
|
- furi_assert(app_instance);
|
|
|
-
|
|
|
- // if back button is pressed
|
|
|
- if (event->type == InputTypePress && event->key == InputKeyBack)
|
|
|
- {
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (event->type == InputTypePress && event->key == InputKeyLeft) // Previous message
|
|
|
- {
|
|
|
- if (flip_feed_info->index > 0)
|
|
|
- {
|
|
|
- flip_feed_info->index--;
|
|
|
- }
|
|
|
- // switch view, free dialog, re-alloc dialog, switch back to dialog
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewWidgetResult);
|
|
|
- free_feed_view();
|
|
|
- // load feed item
|
|
|
- if (!feed_load_post(flip_feed_info->ids[flip_feed_info->index]))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to load nexy feed post");
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (alloc_feed_view())
|
|
|
- {
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to allocate feed dialog");
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (event->type == InputTypePress && event->key == InputKeyRight) // Next message
|
|
|
- {
|
|
|
- // if next message is the last message, then use flip_social_load_initial_feed
|
|
|
- if (flip_feed_info->index == flip_feed_info->count - 1)
|
|
|
- {
|
|
|
- char series_index[16];
|
|
|
- load_char("series_index", series_index, sizeof(series_index));
|
|
|
- flip_feed_info->series_index = atoi(series_index) + 1;
|
|
|
- char new_series_index[16];
|
|
|
- snprintf(new_series_index, sizeof(new_series_index), "%d", flip_feed_info->series_index);
|
|
|
-
|
|
|
- save_char("series_index", new_series_index);
|
|
|
-
|
|
|
- free_flipper_http();
|
|
|
- if (!alloc_flipper_http())
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (!feed_load_initial_feed(app_instance->fhttp, flip_feed_info->series_index))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to load initial feed");
|
|
|
- free_flipper_http();
|
|
|
- return false;
|
|
|
- }
|
|
|
- free_flipper_http();
|
|
|
- // switch view, free dialog, re-alloc dialog, switch back to dialog
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewWidgetResult);
|
|
|
- free_feed_view();
|
|
|
- // load feed item
|
|
|
- if (!feed_load_post(flip_feed_info->ids[flip_feed_info->index]))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to load nexy feed post");
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (alloc_feed_view())
|
|
|
- {
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to allocate feed dialog");
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- if (flip_feed_info->index < flip_feed_info->count - 1)
|
|
|
- {
|
|
|
- flip_feed_info->index++;
|
|
|
- }
|
|
|
- // switch view, free dialog, re-alloc dialog, switch back to dialog
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewWidgetResult);
|
|
|
- free_feed_view();
|
|
|
- // load feed item
|
|
|
- if (!feed_load_post(flip_feed_info->ids[flip_feed_info->index]))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to load nexy feed post");
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (alloc_feed_view())
|
|
|
- {
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to allocate feed dialog");
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (event->type == InputTypePress && event->key == InputKeyOk) // Flip/Unflip
|
|
|
- {
|
|
|
- // Moved to above the is_flipped check
|
|
|
- if (!flip_feed_item->is_flipped)
|
|
|
- {
|
|
|
- // increase the flip count
|
|
|
- flip_feed_item->flips++;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // decrease the flip count
|
|
|
- if (flip_feed_item->flips > 0)
|
|
|
- flip_feed_item->flips--;
|
|
|
- }
|
|
|
- // change the flip status
|
|
|
- flip_feed_item->is_flipped = !flip_feed_item->is_flipped;
|
|
|
-
|
|
|
- // send post request to flip the message
|
|
|
- if (app_instance->login_username_logged_in == NULL)
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Username is NULL");
|
|
|
- return false;
|
|
|
- }
|
|
|
- free_flipper_http();
|
|
|
- if (!alloc_flipper_http())
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- alloc_headers();
|
|
|
- char payload[256];
|
|
|
- snprintf(payload, sizeof(payload), "{\"username\":\"%s\",\"post_id\":\"%u\"}", app_instance->login_username_logged_in, flip_feed_item->id);
|
|
|
- if (flipper_http_request(app_instance->fhttp, POST, "https://www.jblanked.com/flipper/api/feed/flip/", auth_headers, payload))
|
|
|
- {
|
|
|
- // save feed item
|
|
|
- char new_save[512];
|
|
|
- snprintf(new_save, sizeof(new_save), "{\"id\":%u,\"username\":\"%s\",\"message\":\"%s\",\"flip_count\":%u,\"flipped\":%s,\"date_created\":\"%s\"}",
|
|
|
- flip_feed_item->id, flip_feed_item->username, flip_feed_item->message, flip_feed_item->flips, flip_feed_item->is_flipped ? "true" : "false", flip_feed_item->date_created);
|
|
|
- char id[16];
|
|
|
- snprintf(id, sizeof(id), "%u", flip_feed_item->id);
|
|
|
- if (!flip_social_save_post(id, new_save))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to save the feed post");
|
|
|
- free_flipper_http();
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- // switch view, free dialog, re-alloc dialog, switch back to dialog
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewWidgetResult);
|
|
|
- free_feed_view();
|
|
|
- // load feed item
|
|
|
- if (!feed_load_post(flip_feed_info->ids[flip_feed_info->index]))
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to load nexy feed post");
|
|
|
- app_instance->fhttp->state = ISSUE;
|
|
|
- free_flipper_http();
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (alloc_feed_view())
|
|
|
- {
|
|
|
- view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInFeed);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- FURI_LOG_E(TAG, "Failed to allocate feed dialog");
|
|
|
- }
|
|
|
- free_flipper_http();
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
bool alloc_feed_view()
|
|
|
{
|
|
|
if (!app_instance)
|
|
|
@@ -970,8 +650,8 @@ bool alloc_feed_view()
|
|
|
if (!easy_flipper_set_view(
|
|
|
&app_instance->view_feed,
|
|
|
FlipSocialViewLoggedInFeed,
|
|
|
- flip_social_feed_draw_callback,
|
|
|
- flip_social_feed_input_callback,
|
|
|
+ callback_feed_draw,
|
|
|
+ callback_feed_input,
|
|
|
callback_to_submenu_logged_in,
|
|
|
&app_instance->view_dispatcher,
|
|
|
app_instance))
|