From f2237af333d10a1ca07d4dbfc8da8d444ab67a6a Mon Sep 17 00:00:00 2001 From: objnull Date: Thu, 5 Sep 2024 15:57:08 -0400 Subject: [PATCH] Major UI Overhaul. Implemented SceneManager instead of custom built UI system. --- project/backend/ui.c | 497 +++++++++++++++++-------------------------- project/backend/ui.h | 51 ++--- project/flippypass.c | 26 +-- 3 files changed, 219 insertions(+), 355 deletions(-) diff --git a/project/backend/ui.c b/project/backend/ui.c index fbfb88f..15d7a79 100644 --- a/project/backend/ui.c +++ b/project/backend/ui.c @@ -1,330 +1,219 @@ // Header #include "ui.h" -// Functions - Private -void int_to_str(int num, char* str) { - int i = 0; - int is_negative = 0; +// Structures +/* Scenes */ +typedef enum { + FP_Scene_MainMenu, + FP_Scene_Overview, + FP_Scene_View, + FP_Scene_Create, + FP_Scene_Archive, + FP_Scene_About, + FP_Scene_Count // Last Index, says how many scenes there are +} FP_Scene; - // Handle 0 explicitly - if (num == 0) { - str[i++] = '0'; - str[i] = '\0'; - return; - } +/* Types of Views */ +typedef enum { FP_View_Menu, FP_View_Popup } FP_View; - // Handle negative numbers - if (num < 0) { - is_negative = 1; - num = -num; - } +/* All events */ +typedef enum { + FP_Event_SwitchTo_About +} FP_Event; - // Process each digit - while (num != 0) { - str[i++] = (num % 10) + '0'; - num = num / 10; - } +/* Scene events */ +typedef enum { + FP_Scene_MainMenu_Event_View, + FP_Scene_MainMenu_Event_Create, + FP_Scene_MainMenu_Event_Archive, + FP_Scene_MainMenu_Event_About +} FP_Scene_MainMenu_Event; - // If the number was negative, append '-' - if (is_negative) { - str[i++] = '-'; - } +// Page functions +void FP_Scene_Callback_MainMenu(void* context, uint32_t index) { + // Setting context + FP_App* app = context; - // Append the null terminator - str[i] = '\0'; - - // Reverse the string - int start = 0; - int end = i - 1; - while (start < end) { - char temp = str[start]; - str[start] = str[end]; - str[end] = temp; - start++; - end--; + // Switching on Index + switch (index) { + case FP_Scene_MainMenu_Event_About: + scene_manager_handle_custom_event(app->scene_manager, FP_Event_SwitchTo_About); + break; + default: + FURI_LOG_I(TAG, "S_MAINMENU: Unimplemented!"); + break; } } +void FP_Scene_Enter_MainMenu(void* context) { + // Setting context + FP_App* app = context; -// Functions -UIManager* ui_create() { - // Creating the UI Manager - UIManager* result = malloc(sizeof(UIManager)); + // Reset menu for next draw + menu_reset(app->menu); - // Defining basic variables - result->running = true; - result->selection = 0; - result->page = 0; + // Adding items to menu + menu_add_item( + app->menu, + "View Passwords", + NULL, + FP_Scene_MainMenu_Event_View, + FP_Scene_Callback_MainMenu, + app + ); + menu_add_item( + app->menu, + "Create Password", + NULL, + FP_Scene_MainMenu_Event_Create, + FP_Scene_Callback_MainMenu, + app + ); + menu_add_item( + app->menu, + "Archive Actions", + NULL, + FP_Scene_MainMenu_Event_Archive, + FP_Scene_Callback_MainMenu, + app + ); + menu_add_item( + app->menu, + "About", + NULL, + FP_Scene_MainMenu_Event_About, + FP_Scene_Callback_MainMenu, + app + ); - result->p_avail = true; - result->p_ready = false; + // Switching to current view + view_dispatcher_switch_to_view(app->view_dispatcher, FP_View_Menu); +} +void FP_Scene_Exit_MainMenu(void* context) { + // Setting context + FP_App* app = context; - // Creating a GUI - result->gui = furi_record_open(RECORD_GUI); + // Reset menu + menu_reset(app->menu); +} +bool FP_Scene_Event_MainMenu(void* context, SceneManagerEvent event) { + // Setting context + FP_App* app = context; + bool consumed = false; - // Creating a canvas - result->canvas = view_port_alloc(); - view_port_draw_callback_set(result->canvas, ui_draw, result); - view_port_input_callback_set(result->canvas, ui_input, result); - gui_add_view_port(result->gui, result->canvas, GuiLayerFullscreen); + // Switching based on event + if (event.type == SceneManagerEventTypeCustom) { + // We consumed it + consumed = true; - // Creating the manager - result->manager = manager_create(); - manager_loadnames(result->manager, result->manager->page); + // What to do? + switch (event.event) { + case FP_Event_SwitchTo_About: + scene_manager_next_scene(app->scene_manager, FP_Scene_About); + break; + default: + break; + } + } else { + consumed = false; + } - // Returning the UI Manager + // Return result + return consumed; +} + +/* Handlers */ +void (*const FP_Scene_Enter_Handlers[])(void*) = { + FP_Scene_Enter_MainMenu +}; +bool (*const FP_Scene_Event_Handlers[])(void*, SceneManagerEvent) = { + FP_Scene_Event_MainMenu +}; +void (*const FP_Scene_Exit_Handlers[])(void*) = { + FP_Scene_Exit_MainMenu +}; + +/* Event Handlers */ +const SceneManagerHandlers FP_SceneEventHandlers = { + .on_enter_handlers = FP_Scene_Enter_Handlers, + .on_event_handlers = FP_Scene_Event_Handlers, + .on_exit_handlers = FP_Scene_Exit_Handlers, + .scene_num = FP_Scene_Count}; + +// Functions - Private +bool FP_SceneManager_Callback_CustomEvent(void* context, uint32_t custom_event) { + // Is our context okay? + furi_assert(context); + + // Setting context + FP_App* app = context; + + // Return event + return scene_manager_handle_custom_event(app->scene_manager, custom_event); +} +bool FP_SceneManager_Callback_Navigation(void* context) { + // Is our context okay? + furi_assert(context); + + // Setting context + FP_App* app = context; + + // Return navigation + return scene_manager_handle_back_event(app->scene_manager); +} + +// Constructors +FP_App* fp_app_create() { + // Allocate memory for new app variable + FP_App* result = malloc(sizeof(FP_App)); + + // Init Scene Manager + result->scene_manager = scene_manager_alloc(&FP_SceneEventHandlers, result); + + // Init View Dispatcher + result->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(result->view_dispatcher); + + // Allocating all types of views + result->menu = menu_alloc(); + result->popup = popup_alloc(); + + // Event handling + view_dispatcher_set_event_callback_context(result->view_dispatcher, result); + view_dispatcher_set_custom_event_callback(result->view_dispatcher, FP_SceneManager_Callback_CustomEvent); + view_dispatcher_set_navigation_event_callback(result->view_dispatcher, FP_SceneManager_Callback_Navigation); + + // Adding views to dispatcher + view_dispatcher_add_view(result->view_dispatcher, FP_View_Menu, menu_get_view(result->menu)); + view_dispatcher_add_view(result->view_dispatcher, FP_View_Popup, popup_get_view(result->popup)); + + // Return app return result; } -void ui_input(InputEvent* event, void* ctx) { - // Turning the context back into the UI Manager - UIManager* manager = (UIManager*)ctx; +// Functions +void fp_app_run(FP_App* app) { + // Creating GUI + Gui* gui = furi_record_open(RECORD_GUI); - // Getting input - if ((event->type == InputTypePress - || event->type == InputTypeShort) - && manager->p_avail) { - manager->p_avail = false; - manager->p_ready = true; - - switch(event->key) { - case InputKeyUp: - manager->input = Up; - break; - case InputKeyDown: - manager->input = Down; - break; - case InputKeyLeft: - manager->input = Left; - break; - case InputKeyRight: - manager->input = Right; - break; - case InputKeyOk: - manager->input = Ok; - break; - case InputKeyBack: - manager->input = Back; - break; - default: - break; - } - } - if (event->type == InputTypeRelease) { - manager->p_avail = true; - manager->input = None; - } -} -void ui_quit(UIManager* manager) { - if (!(manager->p_ready && manager->input == Back)) {return;} + // Attaching view dispatcher to GUI + view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen); - if(manager->page == 0) { - manager->running = false; - } else if (manager->page == 3) { - manager->p_ready = false; - manager->page = 2; - } else { - manager->p_ready = false; - manager->page = 0; - } -} + // Starting scene + scene_manager_next_scene(app->scene_manager, FP_Scene_MainMenu); -void ui_draw(Canvas* canvas, void* ctx) { - // Context into Result - UIManager* manager = (UIManager*)ctx; + // Start view dispatcher + view_dispatcher_run(app->view_dispatcher); - // Switching page - switch(manager->page){ - case 0: // Main Menu - ui_p_mainmenu(canvas, manager); - break; - case 1: // About Me - ui_p_about(canvas); - break; - case 2: // View Passwords - ui_p_view(canvas, manager); - break; - case 3: // View Password - ui_p_vpass(canvas, manager); - break; - case 4: // Create password - ui_p_cpass(canvas, manager); - break; - } -} -void ui_p_mainmenu(Canvas* canvas, UIManager* manager) { - // Menu Options - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 11, "FlippyPass"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 22, 25, "View Passwords"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 22, 45, "View Archive"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 22, 35, "Create Password"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 22, 55, "About"); - - // Cursor - if(manager->p_ready) { - // We used a press - manager->p_ready = false; - - // Reacting - switch (manager->input){ - case Up: - manager->selection--; - break; - case Down: - manager->selection++; - break; - case Ok: - - switch(manager->selection) { - case 0: // View Passwords - manager->page = 2; - break; - case 1: // Create password - manager->page = 4; - - // Unloading prior password - if (manager->manager->current != NULL) { - FURI_LOG_D(TAG, "Freeing prior password"); - free(manager->manager->current); - } - - // Creating new one - manager->manager->current = pass_create("New Password", "username", "password", 0); - - break; - case 3: // About Me - manager->page = 1; - break; - default: - break; - } - - break; - default: - break; - } - - // Min & Max - if (manager->selection > 3) { - manager->selection = 0; - } else if (manager->selection < 0) { - manager->selection = 3; - } - } - - // Placing the spot at the cursor - canvas_draw_box(canvas, 15, 20 + (manager->selection * 10), 2, 2); -} -void ui_p_about(Canvas* canvas) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 11, "FlippyPass"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 3, 23, "A really easy to use Password"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 3, 32, "Manager for the Flipper-Zero."); -} -void ui_p_view(Canvas* canvas, UIManager* manager) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 11, "FlippyPass"); - - // Counting through password names - for (int i = 0; i < 4; i++) { - if (manager->manager->names[i] != NULL) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 15, 23 + (i * 10), manager->manager->names[i]); - } - } - - // Creating dot - canvas_draw_box(canvas, 10, 18 + (manager->selection * 10), 2, 2); - - if (manager->p_ready) { - manager->p_ready = false; - - switch (manager->input) { - case Up: - manager->selection--; - if(manager->selection < 0) {manager->selection = 0;} - break; - case Down: - manager->selection++; - if(manager->selection > 3) {manager->selection = 3;} - break; - case Left: - manager_switchpage(manager->manager, -1); - break; - case Right: - manager_switchpage(manager->manager, 1); - break; - case Ok: - char* pass_name = manager->manager->names[manager->selection]; - - if (strcmp(pass_name, "") == 0) { - break; - } - - manager_loadpass(manager->manager, pass_name); - manager->page = 3; - break; - default: - break; - } - } - - char page[12]; - int_to_str(manager->manager->page, page + 1); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 106, 62, page); -} -void ui_p_vpass(Canvas* canvas, UIManager* manager) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 11, manager->manager->current->name); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 12, 24, manager->manager->current->user); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 12, 34, manager->manager->current->phrase); - - /* canvas_draw_icon(canvas, 98, 55, &I_ButtonCenter_7x7); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 106, 62, "Send"); */ -} -void ui_p_cpass(Canvas* canvas, UIManager* manager) { - // Displaying password creation screen - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 11, "Create Password"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 20, 23, manager->manager->current->name); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 20, 33, manager->manager->current->user); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 20, 43, manager->manager->current->phrase); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 25, 53, "Done"); -} - -void ui_delete(UIManager* manager) { - manager_delete(manager->manager); - view_port_enabled_set(manager->canvas, false); - gui_remove_view_port(manager->gui, manager->canvas); - view_port_free(manager->canvas); + /* Post Application */ furi_record_close(RECORD_GUI); - free(manager); +} +void fp_app_delete(FP_App* app) { + // Freeing stuff from memory + scene_manager_free(app->scene_manager); + view_dispatcher_remove_view(app->view_dispatcher, FP_View_Menu); + view_dispatcher_remove_view(app->view_dispatcher, FP_View_Popup); + view_dispatcher_free(app->view_dispatcher); + menu_free(app->menu); + popup_free(app->popup); + free(app); } \ No newline at end of file diff --git a/project/backend/ui.h b/project/backend/ui.h index e653d55..e3cac66 100644 --- a/project/backend/ui.h +++ b/project/backend/ui.h @@ -4,52 +4,31 @@ // Libraries #include + #include -#include +#include +#include +#include + +#include +#include #include "app.h" #include "manager.h" // Structures typedef struct { - ViewPort* canvas; - Gui* gui; - enum ui_input { - Up, - Down, - Left, - Right, - - Ok, - Back, - - None - } input; - - Manager* manager; - - int selection; - int page; - - bool running; - bool p_avail; - bool p_ready; -} UIManager; + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + Menu* menu; + Popup* popup; +} FP_App; // Constructors -UIManager* ui_create(); +FP_App* fp_app_create(); // Functions -void ui_input(InputEvent* event, void* ctx); -void ui_quit(UIManager* manager); - -void ui_draw(Canvas* canvas, void* ctx); -void ui_p_mainmenu(Canvas* canvas, UIManager* manager); -void ui_p_about(Canvas* canvas); -void ui_p_view(Canvas* canvas, UIManager* manager); -void ui_p_vpass(Canvas* canvas, UIManager* manager); -void ui_p_cpass(Canvas* canvas, UIManager* manager); - -void ui_delete(UIManager* manager); +void fp_app_run(FP_App* app); +void fp_app_delete(FP_App* app); #endif \ No newline at end of file diff --git a/project/flippypass.c b/project/flippypass.c index a9b4b19..0697a55 100644 --- a/project/flippypass.c +++ b/project/flippypass.c @@ -3,31 +3,27 @@ #include "backend/ui.h" +// Functions +void debug_template() { + store_save("Data", "Apple|example@objnull.net|password|0|Microsoft|person@objnull.net|password|0|Google|user1@objnull.net|password|0|Facebook|user2@objnull.net|password|0|Twitter|user3@objnull.net|password|0|Instagram|user4@objnull.net|password|0|LinkedIn|user5@objnull.net|password|0|GitHub|user6@objnull.net|password|0|Reddit|user7@objnull.net|password|0|Spotify|user8@objnull.net|password|0|Netflix|user9@objnull.net|password|0|Dropbox|user10@objnull.net|password|0|Proton|user54@objnull.net|password|0|Authentik|user19@objnull.net|password|0"); +} + // Entry Point int32_t flippypass_app(void* p) { // Not using P Parameter UNUSED(p); // Saving to a default file: - store_save("Data", "Apple|example@objnull.net|password|0|Microsoft|person@objnull.net|password|0|Google|user1@objnull.net|password|0|Facebook|user2@objnull.net|password|0|Twitter|user3@objnull.net|password|0|Instagram|user4@objnull.net|password|0|LinkedIn|user5@objnull.net|password|0|GitHub|user6@objnull.net|password|0|Reddit|user7@objnull.net|password|0|Spotify|user8@objnull.net|password|0|Netflix|user9@objnull.net|password|0|Dropbox|user10@objnull.net|password|0|Proton|user54@objnull.net|password|0|Authentik|user19@objnull.net|password|0"); + debug_template(); - // Creating the UI struct - UIManager* ui = ui_create(); + // Creating App + FP_App* app = fp_app_create(); - // Drawwing the UI - while(ui->running) { - // Do we want to quit? - ui_quit(ui); - - // Updating canvas - view_port_update(ui->canvas); - - // Delay? - furi_delay_ms(100); - } + // Running app + fp_app_run(app); // Cleanup - ui_delete(ui); + fp_app_delete(app); // Exit App return 0;