From 8b0e4a2aab46c77776d7ce7a7ce7e4f178a5e1a5 Mon Sep 17 00:00:00 2001 From: Derek Jamison Date: Tue, 8 Oct 2024 17:14:11 -0600 Subject: [PATCH] Gemini Text Box (allows redirecting back) --- gemini_app.c | 13 +++--- gemini_app.h | 2 +- gemini_app_i.h | 4 +- scenes/gemini_scene.h | 2 + scenes/gemini_scene_receive_serial.c | 30 +++++++++++--- scenes/gemini_scene_set_name.c | 3 +- views/gemini_text_box.c | 61 ++++++++++++++++++++++++++++ views/gemini_text_box.h | 17 ++++++++ 8 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 views/gemini_text_box.c create mode 100644 views/gemini_text_box.h diff --git a/gemini_app.c b/gemini_app.c index 74a153ccc27..29b8437a462 100644 --- a/gemini_app.c +++ b/gemini_app.c @@ -17,8 +17,9 @@ static bool gemini_app_back_event_callback(void* context) { return scene_manager_handle_back_event(app->scene_manager); } -static bool gemini_app_send_api_key(GeminiApp* app) { +bool gemini_app_send_api_key(GeminiApp* app) { UNUSED(app); + const char* folder_path = EXT_PATH("apps_data/gemini_ia"); const char* key_path = EXT_PATH("apps_data/gemini_ia/key.txt"); bool sent = false; @@ -43,6 +44,8 @@ static bool gemini_app_send_api_key(GeminiApp* app) { } storage_file_close(file); } + } else if (!storage_dir_exists(storage, folder_path)) { + storage_simply_mkdir(storage, folder_path); } furi_record_close(RECORD_STORAGE); @@ -61,8 +64,8 @@ static GeminiApp* gemini_app_alloc() { app->submenu = submenu_alloc(); view_dispatcher_add_view( app->view_dispatcher, GeminiViewSubmenu, submenu_get_view(app->submenu)); - app->text_box = text_box_alloc(); - view_dispatcher_add_view(app->view_dispatcher, GeminiViewTextBox, text_box_get_view(app->text_box)); + app->gemini_text_box = gemini_text_box_alloc(); + view_dispatcher_add_view(app->view_dispatcher, GeminiViewGeminiTextBox, gemini_text_box_get_view(app->gemini_text_box)); app->text_input = text_input_alloc(); view_dispatcher_add_view( app->view_dispatcher, GeminiViewTextInput, text_input_get_view(app->text_input)); @@ -82,12 +85,12 @@ static void gemini_app_free(GeminiApp* app) { uart_helper_free(app->uart_helper); view_dispatcher_remove_view(app->view_dispatcher, GeminiViewSubmenu); view_dispatcher_remove_view(app->view_dispatcher, GeminiViewTextInput); - view_dispatcher_remove_view(app->view_dispatcher, GeminiViewTextBox); + view_dispatcher_remove_view(app->view_dispatcher, GeminiViewGeminiTextBox); view_dispatcher_remove_view(app->view_dispatcher, GeminiViewWidget); scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); submenu_free(app->submenu); - text_box_free(app->text_box); + gemini_text_box_free(app->gemini_text_box); text_input_free(app->text_input); widget_free(app->widget); free(app); diff --git a/gemini_app.h b/gemini_app.h index d5be91a5125..2c6bb928b38 100644 --- a/gemini_app.h +++ b/gemini_app.h @@ -2,7 +2,7 @@ typedef enum { GeminiViewSubmenu, - GeminiViewTextBox, + GeminiViewGeminiTextBox, GeminiViewTextInput, GeminiViewWidget, } GeminiView; diff --git a/gemini_app_i.h b/gemini_app_i.h index 6353f92adbd..c14e2963328 100644 --- a/gemini_app_i.h +++ b/gemini_app_i.h @@ -1,11 +1,11 @@ #pragma once #include "gemini_app.h" +#include "views/gemini_text_box.h" #include #include #include -#include #include #include @@ -17,7 +17,7 @@ struct GeminiApp { SceneManager* scene_manager; ViewDispatcher* view_dispatcher; Submenu* submenu; - TextBox* text_box; + GeminiTextBox* gemini_text_box; TextInput* text_input; Widget* widget; FuriTimer* timer; diff --git a/scenes/gemini_scene.h b/scenes/gemini_scene.h index 570cd029087..c408fe614b0 100644 --- a/scenes/gemini_scene.h +++ b/scenes/gemini_scene.h @@ -27,3 +27,5 @@ extern const SceneManagerHandlers gemini_scene_handlers; #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); #include "gemini_scene_config.h" #undef ADD_SCENE + +void gemini_scene_receive_serial_set_next(void* app, GeminiScene back_scene); diff --git a/scenes/gemini_scene_receive_serial.c b/scenes/gemini_scene_receive_serial.c index 3990aa80ff2..eec2c74c2c2 100644 --- a/scenes/gemini_scene_receive_serial.c +++ b/scenes/gemini_scene_receive_serial.c @@ -5,29 +5,47 @@ static FuriString* contents = NULL; static FuriString* line = NULL; -void gemini_scene_receive_serial_timer_callback(void* context) { +static void gemini_scene_receive_serial_timer_callback(void* context) { GeminiApp* app = context; furi_string_reset(line); bool read = uart_helper_read(app->uart_helper, line, 0); if (read) { - text_box_set_text(app->text_box, ""); + gemini_text_box_set_text(app->gemini_text_box, ""); size_t new_len = furi_string_size(contents) + furi_string_size(line); if(new_len >= 4096) { furi_string_right(contents, new_len / 2); } furi_string_cat(contents, line); - text_box_set_text(app->text_box, furi_string_get_cstr(contents)); + gemini_text_box_set_text(app->gemini_text_box, furi_string_get_cstr(contents)); } } +static bool gemini_text_box_nav_callback(void* context) { + GeminiApp* app = context; + GeminiScene back_scene = (GeminiScene)scene_manager_get_scene_state(app->scene_manager, GeminiSceneReceiveSerial); + if (back_scene == GeminiSceneMainMenu) { + // False should be returned to allow the back event to be handled by the scene manager. + return false; + } else { + scene_manager_search_and_switch_to_another_scene(app->scene_manager, back_scene); + } + return true; +} + +void gemini_scene_receive_serial_set_next(void* context, GeminiScene back_scene) { + GeminiApp* app = context; + scene_manager_set_scene_state(app->scene_manager, GeminiSceneReceiveSerial, (uint32_t)back_scene); +} + void gemini_scene_receive_serial_on_enter(void* context) { GeminiApp* app = context; contents = furi_string_alloc(); line = furi_string_alloc(); - text_box_set_text(app->text_box, ""); - text_box_set_focus(app->text_box, TextBoxFocusEnd); + gemini_text_box_set_text(app->gemini_text_box, ""); + gemini_text_box_set_focus_end(app->gemini_text_box); + gemini_text_box_set_nav_callback(app->gemini_text_box, gemini_text_box_nav_callback, app); app->timer = furi_timer_alloc(gemini_scene_receive_serial_timer_callback, FuriTimerTypePeriodic, app); - view_dispatcher_switch_to_view(app->view_dispatcher, GeminiViewTextBox); + view_dispatcher_switch_to_view(app->view_dispatcher, GeminiViewGeminiTextBox); furi_timer_start(app->timer, REFRESH_RATE); } diff --git a/scenes/gemini_scene_set_name.c b/scenes/gemini_scene_set_name.c index b1888ba475b..10f9092f0d3 100644 --- a/scenes/gemini_scene_set_name.c +++ b/scenes/gemini_scene_set_name.c @@ -17,7 +17,7 @@ void gemini_scene_set_name_on_enter(void* context) { text_input_set_header_text(app->text_input, "Enter your name"); text_input_set_minimum_length(app->text_input, 1); text_buffer[0] = '\0'; - text_input_set_result_callback(app->text_input, gemini_scene_set_name_text_input_callback, app, text_buffer, TEXT_BUFFER_SIZE, true); + text_input_set_result_callback(app->text_input, gemini_scene_set_name_text_input_callback, app, text_buffer, TEXT_BUFFER_SIZE, true); view_dispatcher_switch_to_view(app->view_dispatcher, GeminiViewTextInput); } @@ -29,6 +29,7 @@ bool gemini_scene_set_name_on_event(void* context, SceneManagerEvent event) { case GeminiSceneSetNameEventOk: uart_helper_send(app->uart_helper, text_buffer, TEXT_BUFFER_SIZE); // We want BACK to go back to the main menu, not our current scene. + gemini_scene_receive_serial_set_next(app, GeminiSceneMainMenu); scene_manager_search_and_switch_to_another_scene(app->scene_manager, GeminiSceneReceiveSerial); consumed = true; break; diff --git a/views/gemini_text_box.c b/views/gemini_text_box.c new file mode 100644 index 00000000000..a6306dd7a76 --- /dev/null +++ b/views/gemini_text_box.c @@ -0,0 +1,61 @@ +#include "gemini_text_box.h" +#include +#include + +struct GeminiTextBox { + TextBox* text_box; + View* nav_view; + ViewStack* view_stack; + void* context; + GeminiTextBoxNavCallback nav_callback; +}; + +static bool gemini_text_box_input_callback(InputEvent* event, void* context) { + GeminiTextBox* gemini_text_box = context; + UNUSED(gemini_text_box); + UNUSED(event); + + if (event->type == InputTypeShort && event->key == InputKeyBack) { + if (gemini_text_box->nav_callback) { + return gemini_text_box->nav_callback(gemini_text_box->context); + } + } + + return false; +} + +GeminiTextBox* gemini_text_box_alloc() { + GeminiTextBox* gemini_text_box = malloc(sizeof(GeminiTextBox)); + gemini_text_box->view_stack = view_stack_alloc(); + gemini_text_box->text_box = text_box_alloc(); + view_stack_add_view(gemini_text_box->view_stack, text_box_get_view(gemini_text_box->text_box)); + gemini_text_box->nav_view = view_alloc(); + view_set_context(gemini_text_box->nav_view, gemini_text_box); + view_set_input_callback(gemini_text_box->nav_view, gemini_text_box_input_callback); + view_stack_add_view(gemini_text_box->view_stack, gemini_text_box->nav_view); + return gemini_text_box; +} + +void gemini_text_box_free(GeminiTextBox* text_box) { + furi_check(text_box); + text_box_free(text_box->text_box); + view_stack_free(text_box->view_stack); + free(text_box); +} + +void gemini_text_box_set_nav_callback(GeminiTextBox* text_box, GeminiTextBoxNavCallback callback, void* context) { + text_box->nav_callback = callback; + text_box->context = context; +} + +void gemini_text_box_set_text(GeminiTextBox* text_box, const char* text) { + text_box_set_text(text_box->text_box, text); +} + +void gemini_text_box_set_focus_end(GeminiTextBox* text_box) { + text_box_set_focus(text_box->text_box, TextBoxFocusEnd); +} + +View* gemini_text_box_get_view(GeminiTextBox* text_box) { + return view_stack_get_view(text_box->view_stack); +} \ No newline at end of file diff --git a/views/gemini_text_box.h b/views/gemini_text_box.h new file mode 100644 index 00000000000..f41826e05cd --- /dev/null +++ b/views/gemini_text_box.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +typedef struct GeminiTextBox GeminiTextBox; + +typedef bool (*GeminiTextBoxNavCallback)(void* context); + +GeminiTextBox* gemini_text_box_alloc(); +void gemini_text_box_free(GeminiTextBox* text_box); +void gemini_text_box_set_nav_callback( + GeminiTextBox* text_box, + GeminiTextBoxNavCallback callback, + void* context); +void gemini_text_box_set_text(GeminiTextBox* text_box, const char* text); +void gemini_text_box_set_focus_end(GeminiTextBox* text_box); +View* gemini_text_box_get_view(GeminiTextBox* text_box);