Browse Source

scenes: rework scene management

Following more of the intended paradigms of view_dispatcher and
scene_manager. Scene callbacks now all send view dispatcher custom
events rather than navigating scene transitions within them. This
means scenes are no longer in the callback when exit/enter pairs
are called which is the correct way to handle it.

Signed-off-by: Kris Bahnsen <Kris@KBEmbedded.com>
Kris Bahnsen 1 year ago
parent
commit
fcaa48fabe

+ 4 - 3
src/include/pokemon_app.h

@@ -42,11 +42,12 @@ struct pokemon_fap {
 typedef struct pokemon_fap PokemonFap;
 
 typedef enum {
-    AppViewMainMenu,
-    AppViewOpts, // Generic view ID meant for module re-use
+    AppViewSubmenu,
+    AppViewTextInput,
+    AppViewVariableItem,
+    AppViewDialogEx,
     AppViewSelectPokemon,
     AppViewTrade,
-    AppViewExitConfirm,
 } AppView;
 
 #endif /* POKEMON_APP_H */

+ 51 - 26
src/pokemon_app.c

@@ -3,48 +3,68 @@
 
 #include <src/include/pokemon_app.h>
 #include <src/include/pokemon_data.h>
-#include <src/scenes/include/pokemon_menu.h>
 #include <src/views/trade.h>
 #include <src/views/select_pokemon.h>
 #include <src/include/pokemon_char_encode.h>
 
 #include <src/scenes/include/pokemon_scene.h>
 
+bool pokemon_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+
+    return scene_manager_handle_custom_event(pokemon_fap->scene_manager, event);
+}
+
+bool pokemon_back_event_callback(void* context) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    return scene_manager_handle_back_event(pokemon_fap->scene_manager);
+}
+
+
 PokemonFap* pokemon_alloc() {
     PokemonFap* pokemon_fap = (PokemonFap*)malloc(sizeof(PokemonFap));
+    ViewDispatcher* view_dispatcher = NULL;
 
     // View dispatcher
-    pokemon_fap->view_dispatcher = view_dispatcher_alloc();
+    view_dispatcher = view_dispatcher_alloc();
+    pokemon_fap->view_dispatcher = view_dispatcher;
 
-    view_dispatcher_enable_queue(pokemon_fap->view_dispatcher);
-    view_dispatcher_set_event_callback_context(pokemon_fap->view_dispatcher, pokemon_fap);
+    view_dispatcher_enable_queue(view_dispatcher);
+    view_dispatcher_set_event_callback_context(view_dispatcher, pokemon_fap);
+    view_dispatcher_set_custom_event_callback(view_dispatcher, pokemon_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(view_dispatcher, pokemon_back_event_callback);
     view_dispatcher_attach_to_gui(
-        pokemon_fap->view_dispatcher,
+        view_dispatcher,
         (Gui*)furi_record_open(RECORD_GUI),
         ViewDispatcherTypeFullscreen);
 
-    // Set up defaults
+    // Set up pinout defaults
     memcpy(&pokemon_fap->pins, &common_pinouts[PINOUT_ORIGINAL], sizeof(struct gblink_pins));
 
-    /* Set up gui modules used. It would be nice if these could be allocated and
-     * freed as needed, however, the scene manager still requires pointers that
-     * get set up as a part of the scene. Therefore, individual scene's exit
-     * callbacks cannot free the buffer.
-     *
-     * In order to do this properly, I think each scene, or maybe common to all
-     * scenes, would end up needing to set a delayed callback of some kind. But
-     * I'm not sure how to guarantee this gets called in a reasonable amount of
-     * time.
-     */
+    // Text input
     pokemon_fap->text_input = text_input_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewTextInput, text_input_get_view(pokemon_fap->text_input));
+
+    // Submenu
     pokemon_fap->submenu = submenu_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewSubmenu, submenu_get_view(pokemon_fap->submenu));
+
+    // Variable Item List
     pokemon_fap->variable_item_list = variable_item_list_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewVariableItem, variable_item_list_get_view(pokemon_fap->variable_item_list));
+
+    // DialogEx
     pokemon_fap->dialog_ex = dialog_ex_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewDialogEx, dialog_ex_get_view(pokemon_fap->dialog_ex));
 
-    // Set up menu scene
+    // Scene manager
     pokemon_fap->scene_manager = scene_manager_alloc(&pokemon_scene_handlers, pokemon_fap);
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewMainMenu, submenu_get_view(pokemon_fap->submenu));
     scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneMainMenu);
 
     return pokemon_fap;
@@ -53,19 +73,24 @@ PokemonFap* pokemon_alloc() {
 void free_app(PokemonFap* pokemon_fap) {
     furi_assert(pokemon_fap);
 
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
+    // Submenu
+    submenu_free(pokemon_fap->submenu);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+
+    text_input_free(pokemon_fap->text_input);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewTextInput);
+
+    variable_item_list_free(pokemon_fap->variable_item_list);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
+
+    dialog_ex_free(pokemon_fap->dialog_ex);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewDialogEx);
 
     view_dispatcher_free(pokemon_fap->view_dispatcher);
 
     // Free scenes
     scene_manager_free(pokemon_fap->scene_manager);
 
-    // Free gui modules
-    submenu_free(pokemon_fap->submenu);
-    text_input_free(pokemon_fap->text_input);
-    variable_item_list_free(pokemon_fap->variable_item_list);
-    dialog_ex_free(pokemon_fap->dialog_ex);
-
     // Close records
     furi_record_close(RECORD_GUI);
 

+ 0 - 10
src/scenes/include/pokemon_menu.h

@@ -1,10 +0,0 @@
-#ifndef POKEMON_MENU_H
-#define POKEMON_MENU_H
-
-#pragma once
-
-#include <gui/scene_manager.h>
-
-bool main_menu_back_event_callback(void* context);
-
-#endif // POKEMON_MENU_H

+ 6 - 0
src/scenes/include/pokemon_scene.h

@@ -10,6 +10,12 @@
 typedef enum {
 #include "pokemon_scene_config.h"
     PokemonSceneNum,
+    /* Magic number to send on an event to search through scene history and
+     * change to a previous scene.
+     */
+    PokemonSceneSearch = (1 << 30),
+    /* Magic number to send on an event to trigger going back a scene */
+    PokemonSceneBack = (1 << 31),
 } PokemonScene;
 #undef ADD_SCENE
 

+ 3 - 21
src/scenes/pokemon_exit_confirm.c

@@ -9,16 +9,10 @@
 #include <src/views/select_pokemon.h>
 #include <src/views/trade.h>
 
-static bool pokemon_scene_exit_confirm_back_event_callback(void* context) {
-    UNUSED(context);
-
-    return true;
-}
-
 static void pokemon_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
     PokemonFap* pokemon_fap = context;
 
-    scene_manager_handle_custom_event(pokemon_fap->scene_manager, result);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, result);
 }
 
 void pokemon_scene_exit_confirm_on_enter(void* context) {
@@ -42,16 +36,7 @@ void pokemon_scene_exit_confirm_on_enter(void* context) {
     dialog_ex_set_context(dialog_ex, pokemon_fap);
     dialog_ex_set_result_callback(dialog_ex, pokemon_scene_exit_confirm_dialog_callback);
 
-    /* Disable the existing navigation event handler to prevent handling further
-     * back events. Going back to the main menu as well as going back to the
-     * gen menu will re-enable the proper navigation handler.
-     */
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, pokemon_scene_exit_confirm_back_event_callback);
-
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, dialog_ex_get_view(pokemon_fap->dialog_ex));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewDialogEx);
 }
 
 bool pokemon_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
@@ -91,9 +76,6 @@ bool pokemon_scene_exit_confirm_on_event(void* context, SceneManagerEvent event)
 }
 
 void pokemon_scene_exit_confirm_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    UNUSED(context);
 }
 

+ 72 - 68
src/scenes/pokemon_gen.c

@@ -9,66 +9,30 @@
 
 #include <src/scenes/include/pokemon_scene.h>
 
-#include <src/scenes/include/pokemon_menu.h>
 #include <src/include/pokemon_attribute.h>
 
 static void scene_change_from_main_cb(void* context, uint32_t index) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
-    /* Reuse of scenes to allow for using the same functions to set names */
-    switch(index) {
-    case PokemonSceneNickname:
-    case PokemonSceneOTName:
-    case PokemonSceneUnownForm:
-        scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneNickname, index);
-        break;
-    case PokemonSceneLevel:
-    case PokemonSceneOTID:
-        scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneLevel, index);
-        break;
-    case PokemonSceneGender:
-        if(pokemon_gender_is_static(
-               pokemon_fap->pdata,
-               table_stat_base_get(
-                   pokemon_fap->pdata->pokemon_table,
-                   pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE),
-                   STAT_BASE_GENDER_RATIO,
-                   NONE)))
-            return;
-        break;
-    }
-
-    /* Set the navigation handler back to the basic one in the main menu. We only
-     * want gen_back_event_callback from this menu as going back from the gen menu
-     * means we need to free pdata.
-     */
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, main_menu_back_event_callback);
-
     /* Set scene state to the current index so we can have that element highlighted when
-     * we return.
+     * we return. Note that GenI scene is always used as a reference for this in this
+     * scene, whether its GenI or GenII.
      */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, index);
-}
-
-bool gen_back_event_callback(void* context) {
-    furi_assert(context);
-    PokemonFap* pokemon_fap = context;
 
-    scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneExitConfirm);
-    return true;
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, index);
 }
 
 void pokemon_scene_gen_on_enter(void* context) {
     char buf[32];
     char name_buf[11]; // All name buffers are 11 bytes at most, including term
     PokemonFap* pokemon_fap = (PokemonFap*)context;
+    PokemonData* pdata = pokemon_fap->pdata;
     int pkmn_num;
     uint32_t state;
 
     // Set up trade party struct
-    if(!pokemon_fap->pdata) {
+    if(!pdata) {
         state = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade);
         switch(state) {
         case PokemonSceneGenITrade:
@@ -82,6 +46,7 @@ void pokemon_scene_gen_on_enter(void* context) {
             break;
         }
         pokemon_fap->pdata = pokemon_data_alloc(state);
+	pdata = pokemon_fap->pdata;
 
         /* Clear the scene state as this is the first entry in to this scene
 	 * we definitely want to be completely reset.
@@ -91,18 +56,17 @@ void pokemon_scene_gen_on_enter(void* context) {
         /* Allocate select and trade views */
         /* Allocates its own view and adds it to the main view_dispatcher */
         pokemon_fap->select = select_pokemon_alloc(
-            pokemon_fap->pdata,
+            pdata,
             pokemon_fap->view_dispatcher,
-            pokemon_fap->scene_manager,
             AppViewSelectPokemon);
 
         // Trade View
         /* Allocates its own view and adds it to the main view_dispatcher */
         pokemon_fap->trade = trade_alloc(
-            pokemon_fap->pdata, &pokemon_fap->pins, pokemon_fap->view_dispatcher, AppViewTrade);
+            pdata, &pokemon_fap->pins, pokemon_fap->view_dispatcher, AppViewTrade);
     }
 
-    pkmn_num = pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE);
+    pkmn_num = pokemon_stat_get(pdata, STAT_NUM, NONE);
 
     /* Clear the scene state of the Move scene since that is used to set the
      * highlighted menu item.
@@ -119,11 +83,11 @@ void pokemon_scene_gen_on_enter(void* context) {
         buf,
         sizeof(buf),
         "Pokemon:   %s",
-        table_stat_name_get(pokemon_fap->pdata->pokemon_table, pkmn_num));
+        table_stat_name_get(pdata->pokemon_table, pkmn_num));
     submenu_add_item(
         pokemon_fap->submenu, buf, PokemonSceneSelect, scene_change_from_main_cb, pokemon_fap);
 
-    pokemon_name_get(pokemon_fap->pdata, STAT_NICKNAME, name_buf, sizeof(name_buf));
+    pokemon_name_get(pdata, STAT_NICKNAME, name_buf, sizeof(name_buf));
     snprintf(buf, sizeof(buf), "Nickname:  %s", name_buf);
     submenu_add_item(
         pokemon_fap->submenu, buf, PokemonSceneNickname, scene_change_from_main_cb, pokemon_fap);
@@ -132,18 +96,18 @@ void pokemon_scene_gen_on_enter(void* context) {
         buf,
         sizeof(buf),
         "Level:           %d",
-        pokemon_stat_get(pokemon_fap->pdata, STAT_LEVEL, NONE));
+        pokemon_stat_get(pdata, STAT_LEVEL, NONE));
     submenu_add_item(
         pokemon_fap->submenu, buf, PokemonSceneLevel, scene_change_from_main_cb, pokemon_fap);
 
-    if(pokemon_fap->pdata->gen == GEN_II) {
+    if(pdata->gen == GEN_II) {
         snprintf(
             buf,
             sizeof(buf),
             "Held Item:   %s",
             namedlist_name_get_index(
-                pokemon_fap->pdata->item_list,
-                pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, NONE)));
+                pdata->item_list,
+                pokemon_stat_get(pdata, STAT_HELD_ITEM, NONE)));
         submenu_add_item(
             pokemon_fap->submenu, buf, PokemonSceneItem, scene_change_from_main_cb, pokemon_fap);
     }
@@ -155,7 +119,7 @@ void pokemon_scene_gen_on_enter(void* context) {
         scene_change_from_main_cb,
         pokemon_fap);
 
-    if(pokemon_fap->pdata->gen == GEN_I) {
+    if(pdata->gen == GEN_I) {
         submenu_add_item(
             pokemon_fap->submenu,
             "Select Types",
@@ -167,30 +131,30 @@ void pokemon_scene_gen_on_enter(void* context) {
     submenu_add_item(
         pokemon_fap->submenu,
         namedlist_name_get_index(
-            pokemon_fap->pdata->stat_list, pokemon_stat_get(pokemon_fap->pdata, STAT_SEL, NONE)),
+            pdata->stat_list, pokemon_stat_get(pdata, STAT_SEL, NONE)),
         PokemonSceneStats,
         scene_change_from_main_cb,
         pokemon_fap);
 
-    if(pokemon_fap->pdata->gen == GEN_II) {
+    if(pdata->gen == GEN_II) {
         snprintf(
             buf,
             sizeof(buf),
             "Shiny:             %s",
-            pokemon_is_shiny(pokemon_fap->pdata) ? "Yes" : "No");
+            pokemon_is_shiny(pdata) ? "Yes" : "No");
         submenu_add_item(
             pokemon_fap->submenu, buf, PokemonSceneShiny, scene_change_from_main_cb, pokemon_fap);
 
-        snprintf(buf, sizeof(buf), "Gender:         %s", pokemon_gender_get(pokemon_fap->pdata));
+        snprintf(buf, sizeof(buf), "Gender:         %s", pokemon_gender_get(pdata));
         submenu_add_item(
             pokemon_fap->submenu, buf, PokemonSceneGender, scene_change_from_main_cb, pokemon_fap);
 
-        snprintf(buf, sizeof(buf), "Pokerus:       %s", pokerus_get_status_str(pokemon_fap->pdata));
+        snprintf(buf, sizeof(buf), "Pokerus:       %s", pokerus_get_status_str(pdata));
         submenu_add_item(
             pokemon_fap->submenu, buf, PokemonScenePokerus, scene_change_from_main_cb, pokemon_fap);
 
-        if(pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE) == 0xC8) { // Unown
-            snprintf(buf, sizeof(buf), "Unown Form: %c", unown_form_get(pokemon_fap->pdata));
+        if(pokemon_stat_get(pdata, STAT_NUM, NONE) == 0xC8) { // Unown
+            snprintf(buf, sizeof(buf), "Unown Form: %c", unown_form_get(pdata));
             submenu_add_item(
                 pokemon_fap->submenu,
                 buf,
@@ -204,11 +168,11 @@ void pokemon_scene_gen_on_enter(void* context) {
         buf,
         sizeof(buf),
         "OT ID#:          %05d",
-        pokemon_stat_get(pokemon_fap->pdata, STAT_OT_ID, NONE));
+        pokemon_stat_get(pdata, STAT_OT_ID, NONE));
     submenu_add_item(
         pokemon_fap->submenu, buf, PokemonSceneOTID, scene_change_from_main_cb, pokemon_fap);
 
-    pokemon_name_get(pokemon_fap->pdata, STAT_OT_NAME, name_buf, sizeof(name_buf));
+    pokemon_name_get(pdata, STAT_OT_NAME, name_buf, sizeof(name_buf));
     snprintf(buf, sizeof(buf), "OT Name:      %s", name_buf);
     submenu_add_item(
         pokemon_fap->submenu, buf, PokemonSceneOTName, scene_change_from_main_cb, pokemon_fap);
@@ -223,16 +187,56 @@ void pokemon_scene_gen_on_enter(void* context) {
         pokemon_fap->submenu,
         scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade));
 
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, gen_back_event_callback);
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
 }
 
 bool pokemon_scene_gen_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+    PokemonData* pdata = pokemon_fap->pdata;
+    uint8_t pokemon_num;
+    uint8_t gender_ratio;
+
+
+    /* If the user tries to go back from this scene to main menu, instead
+     * shift to the exit confirmation scene. That scene will handle freeing
+     * data as well as going back to the main menu.
+     */
+    if (event.type == SceneManagerEventTypeBack) {
+        scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneExitConfirm);
+        consumed = true;
+    }
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+
+        /* Reuse of scenes to allow for using the same functions to set names */
+        switch(event.event) {
+        case PokemonSceneNickname:
+        case PokemonSceneOTName:
+        case PokemonSceneUnownForm:
+            scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneNickname, event.event);
+            break;
+        case PokemonSceneLevel:
+        case PokemonSceneOTID:
+            scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneLevel, event.event);
+            break;
+        case PokemonSceneGender:
+            pokemon_num = pokemon_stat_get(pdata, STAT_NUM, NONE);
+            gender_ratio = table_stat_base_get(pdata->pokemon_table, pokemon_num, STAT_BASE_GENDER_RATIO, NONE);
+            /* If the pokemon's gender is static (always male, always female,
+             * or unknown), then don't transition to the gender selection scene.
+             */
+            if(pokemon_gender_is_static(pdata, gender_ratio))
+                goto out;
+            break;
+        }
+
+        scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+    }
+
+out:
+    return consumed;
 }
 
 void pokemon_scene_gen_on_exit(void* context) {

+ 11 - 6
src/scenes/pokemon_gender.c

@@ -11,7 +11,7 @@ static void select_gender_selected_callback(void* context, uint32_t index) {
 
     pokemon_gender_set(pokemon_fap->pdata, index);
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
 void pokemon_scene_select_gender_on_enter(void* context) {
@@ -26,12 +26,17 @@ void pokemon_scene_select_gender_on_enter(void* context) {
         pokemon_fap->submenu, "Male", GENDER_MALE, select_gender_selected_callback, pokemon_fap);
 }
 
-bool pokemon_scene_select_gender_on_event(void* context, SceneManagerEvent event)
-{
-	UNUSED(event);
-	UNUSED(context);
+bool pokemon_scene_select_gender_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
 
-	return false;
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_gender_on_exit(void* context) {

+ 36 - 10
src/scenes/pokemon_item.c

@@ -23,7 +23,7 @@ static void select_item_selected_callback(void* context, uint32_t index) {
             pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, item)));
 
     /* Move back to Gen menu. This assumes this submenu is only ever used in Gen II */
-    scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, PokemonSceneGenIITrade);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, (PokemonSceneSearch | PokemonSceneGenIITrade));
 }
 
 static void select_item_index_callback(void* context, uint32_t index) {
@@ -31,7 +31,7 @@ static void select_item_index_callback(void* context, uint32_t index) {
 
     /* Move to next scene */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneItemSet);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneItemSet);
 }
 
 void pokemon_scene_select_item_on_enter(void* context) {
@@ -67,12 +67,27 @@ void pokemon_scene_select_item_on_enter(void* context) {
         pokemon_fap->submenu,
         scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet));
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet, 0);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
 }
 
 bool pokemon_scene_select_item_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_item_on_exit(void* context) {
@@ -104,12 +119,23 @@ void pokemon_scene_select_item_set_on_enter(void* context) {
     }
 }
 
-bool pokemon_scene_select_item_set_on_event(void* context, SceneManagerEvent event)
-{
-	UNUSED(event);
-	UNUSED(context);
+bool pokemon_scene_select_item_set_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
 
-	return false;
+    return consumed;
 }
 
 void pokemon_scene_select_item_set_on_exit(void* context) {

+ 11 - 13
src/scenes/pokemon_menu.c

@@ -16,13 +16,8 @@ static void scene_change_from_main_cb(void* context, uint32_t index) {
      * we return.
      */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMainMenu, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, index);
-}
 
-bool main_menu_back_event_callback(void* context) {
-    furi_assert(context);
-    PokemonFap* pokemon_fap = context;
-    return scene_manager_handle_back_event(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, index);
 }
 
 void pokemon_scene_main_menu_on_enter(void* context) {
@@ -54,16 +49,19 @@ void pokemon_scene_main_menu_on_enter(void* context) {
         pokemon_fap->submenu,
         scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMainMenu));
 
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, main_menu_back_event_callback);
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
 }
 
 bool pokemon_scene_main_menu_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_main_menu_on_exit(void* context) {

+ 53 - 19
src/scenes/pokemon_move.c

@@ -31,7 +31,7 @@ static void select_move_selected_callback(void* context, uint32_t index) {
         (int)move);
 
     /* Move back to move menu */
-    scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, PokemonSceneMove);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, (PokemonSceneMove | PokemonSceneSearch));
 }
 
 static void select_move_index_callback(void* context, uint32_t index) {
@@ -39,7 +39,7 @@ static void select_move_index_callback(void* context, uint32_t index) {
 
     /* Move to next scene */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneMoveSet);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneMoveSet);
 }
 
 static void select_move_number_callback(void* context, uint32_t index) {
@@ -49,7 +49,7 @@ static void select_move_number_callback(void* context, uint32_t index) {
      * This doubles as the move slot we're going to write to later.
      */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMove, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneMoveIndex);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneMoveIndex);
 }
 
 void pokemon_scene_select_move_on_enter(void* context) {
@@ -80,12 +80,27 @@ void pokemon_scene_select_move_on_enter(void* context) {
 
     /* Clear cursor position on MoveIndex */
     scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex, 0);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
 }
 
 bool pokemon_scene_select_move_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_move_on_exit(void* context) {
@@ -147,9 +162,22 @@ void pokemon_scene_select_move_index_on_enter(void* context) {
 }
 
 bool pokemon_scene_select_move_index_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_move_index_on_exit(void* context) {
@@ -182,18 +210,24 @@ void pokemon_scene_select_move_set_on_enter(void* context) {
 }
 
 bool pokemon_scene_select_move_set_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_move_set_on_exit(void* context) {
     UNUSED(context);
 }
-
-void generic_scene_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
-}

+ 13 - 10
src/scenes/pokemon_name_input.c

@@ -73,7 +73,7 @@ static bool select_name_input_validator(const char* text, FuriString* error, voi
 static void select_name_input_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
 void pokemon_scene_select_name_on_enter(void* context) {
@@ -119,20 +119,23 @@ void pokemon_scene_select_name_on_enter(void* context) {
         pokemon_fap->text_input, select_name_input_callback, pokemon_fap, name_buf, len, true);
     text_input_set_header_text(pokemon_fap->text_input, header);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTextInput);
 }
 
 bool pokemon_scene_select_name_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_name_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
+    UNUSED(context);
 
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
 }

+ 13 - 11
src/scenes/pokemon_number_input.c

@@ -63,7 +63,7 @@ static bool select_number_input_validator(const char* text, FuriString* error, v
 static void select_number_input_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
 void pokemon_scene_select_number_on_enter(void* context) {
@@ -97,20 +97,22 @@ void pokemon_scene_select_number_on_enter(void* context) {
         pokemon_fap->text_input, select_number_input_callback, pokemon_fap, number_buf, len, true);
     text_input_set_header_text(pokemon_fap->text_input, header);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTextInput);
 }
 
 bool pokemon_scene_select_number_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_number_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    UNUSED(context);
 }

+ 2 - 9
src/scenes/pokemon_pins.c

@@ -149,11 +149,7 @@ void pokemon_scene_select_pins_on_enter(void* context) {
 
     select_pins_rebuild_list(pokemon_fap);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher,
-        AppViewOpts,
-        variable_item_list_get_view(pokemon_fap->variable_item_list));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
 }
 
 bool pokemon_scene_select_pins_on_event(void* context, SceneManagerEvent event) {
@@ -163,8 +159,5 @@ bool pokemon_scene_select_pins_on_event(void* context, SceneManagerEvent event)
 }
 
 void pokemon_scene_select_pins_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    UNUSED(context);
 }

+ 2 - 9
src/scenes/pokemon_pokerus.c

@@ -138,11 +138,7 @@ void pokemon_scene_select_pokerus_on_enter(void* context) {
 
     select_pokerus_rebuild_list(pokemon_fap);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher,
-        AppViewOpts,
-        variable_item_list_get_view(pokemon_fap->variable_item_list));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
 }
 
 bool pokemon_scene_select_pokerus_on_event(void* context, SceneManagerEvent event) {
@@ -152,8 +148,5 @@ bool pokemon_scene_select_pokerus_on_event(void* context, SceneManagerEvent even
 }
 
 void pokemon_scene_select_pokerus_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    UNUSED(context);
 }

+ 12 - 3
src/scenes/pokemon_select.c

@@ -1,5 +1,7 @@
 #include <src/include/pokemon_app.h>
 
+#include <src/scenes/include/pokemon_scene.h>
+
 void pokemon_scene_select_pokemon_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     // switch to select pokemon scene
@@ -9,9 +11,16 @@ void pokemon_scene_select_pokemon_on_enter(void* context) {
 }
 
 bool pokemon_scene_select_pokemon_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_pokemon_on_exit(void* context) {

+ 11 - 4
src/scenes/pokemon_shiny.c

@@ -10,7 +10,7 @@ static void select_shiny_selected_callback(void* context, uint32_t index) {
 
     pokemon_set_shiny(pokemon_fap->pdata, (bool)index);
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
 void pokemon_scene_select_shiny_on_enter(void* context) {
@@ -26,9 +26,16 @@ void pokemon_scene_select_shiny_on_enter(void* context) {
 }
 
 bool pokemon_scene_select_shiny_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_shiny_on_exit(void* context) {

+ 12 - 3
src/scenes/pokemon_stats.c

@@ -29,12 +29,21 @@ void pokemon_scene_select_stats_on_enter(void* context) {
             select_stats_selected_callback,
             pokemon_fap);
     }
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
 }
 
 bool pokemon_scene_select_stats_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
 }
 
 void pokemon_scene_select_stats_on_exit(void* context) {

+ 2 - 9
src/scenes/pokemon_type.c

@@ -69,11 +69,7 @@ void pokemon_scene_select_type_on_enter(void* context) {
             vitype[i], namedlist_name_get_pos(pokemon_fap->pdata->type_list, pos));
     }
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher,
-        AppViewOpts,
-        variable_item_list_get_view(pokemon_fap->variable_item_list));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
 }
 
 bool pokemon_scene_select_type_on_event(void* context, SceneManagerEvent event) {
@@ -83,8 +79,5 @@ bool pokemon_scene_select_type_on_event(void* context, SceneManagerEvent event)
 }
 
 void pokemon_scene_select_type_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    UNUSED(context);
 }

+ 6 - 6
src/views/select_pokemon.c

@@ -1,10 +1,12 @@
 #include <gui/elements.h>
+#include <gui/view_dispatcher.h>
 #include <pokemon_icons.h>
 
-#include <src/scenes/include/pokemon_menu.h>
 #include <src/include/pokemon_app.h>
 #include <src/include/pokemon_data.h>
 
+#include <src/scenes/include/pokemon_scene.h>
+
 struct select_model {
     uint8_t curr_pokemon;
     const void* pokemon_table;
@@ -15,7 +17,7 @@ struct select_model {
 struct select_ctx {
     View* view;
     PokemonData* pdata;
-    SceneManager* scene_manager;
+    ViewDispatcher* view_dispatcher;
 };
 
 static void select_pokemon_render_callback(Canvas* canvas, void* model) {
@@ -73,7 +75,7 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) {
     /* Advance to next view with the selected pokemon */
     case InputKeyOk:
         pokemon_stat_set(select->pdata, STAT_NUM, NONE, selected_pokemon);
-        scene_manager_previous_scene(select->scene_manager);
+	view_dispatcher_send_custom_event(select->view_dispatcher, PokemonSceneBack);
         consumed = true;
         break;
 
@@ -148,7 +150,6 @@ void select_pokemon_enter_callback(void* context) {
 void* select_pokemon_alloc(
     PokemonData* pdata,
     ViewDispatcher* view_dispatcher,
-    SceneManager* scene_manager,
     uint32_t viewid) {
     furi_assert(pdata);
 
@@ -156,8 +157,7 @@ void* select_pokemon_alloc(
 
     select->view = view_alloc();
     select->pdata = pdata;
-    select->scene_manager = scene_manager;
-    select->pdata = pdata;
+    select->view_dispatcher = view_dispatcher;
 
     view_set_context(select->view, select);
     view_allocate_model(select->view, ViewModelTypeLockFree, sizeof(struct select_model));

+ 0 - 1
src/views/select_pokemon.h

@@ -9,7 +9,6 @@
 void* select_pokemon_alloc(
     PokemonData* pdata,
     ViewDispatcher* view_dispatcher,
-    SceneManager* scene_manager,
     uint32_t viewid);
 
 void select_pokemon_free(ViewDispatcher* view_dispatcher, uint32_t viewid, void* select_ctx);