scene_items.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include <furi.h>
  2. #include <gui/view_dispatcher.h>
  3. #include <gui/scene_manager.h>
  4. #include <gui/modules/button_menu.h>
  5. #include <gui/modules/dialog_ex.h>
  6. #include <notification/notification_messages.h>
  7. #include "quac.h"
  8. #include "scenes.h"
  9. #include "scene_items.h"
  10. #include "../actions/action.h"
  11. #include "../views/action_menu.h"
  12. #include <lib/toolbox/path.h>
  13. void scene_items_item_callback(void* context, int32_t index, InputType type) {
  14. App* app = context;
  15. if(type == InputTypeShort || type == InputTypeRelease) {
  16. app->selected_item = index;
  17. view_dispatcher_send_custom_event(app->view_dispatcher, Event_ButtonPressed);
  18. } else {
  19. // do nothing
  20. }
  21. }
  22. // For each scene, implement handler callbacks
  23. void scene_items_on_enter(void* context) {
  24. App* app = context;
  25. ActionMenu* menu = app->action_menu;
  26. action_menu_reset(menu);
  27. if(app->settings.layout == QUAC_APP_LANDSCAPE)
  28. action_menu_set_layout(menu, ActionMenuLayoutLandscape);
  29. else
  30. action_menu_set_layout(menu, ActionMenuLayoutPortrait);
  31. action_menu_set_show_icons(menu, app->settings.show_icons);
  32. action_menu_set_show_headers(menu, app->settings.show_headers);
  33. ItemsView* items_view = app->items_view;
  34. FURI_LOG_I(TAG, "items on_enter: [%d] %s", app->depth, furi_string_get_cstr(items_view->path));
  35. furi_delay_ms(500);
  36. const char* header = furi_string_get_cstr(items_view->name);
  37. action_menu_set_header(menu, header);
  38. size_t item_view_size = ItemArray_size(items_view->items);
  39. if(item_view_size > 0) {
  40. ItemArray_it_t iter;
  41. int32_t index = 0;
  42. for(ItemArray_it(iter, items_view->items); !ItemArray_end_p(iter);
  43. ItemArray_next(iter), ++index) {
  44. const char* label = furi_string_get_cstr(ItemArray_cref(iter)->name);
  45. ActionMenuItemType type;
  46. // TODO: Fix this with an array/map
  47. switch(ItemArray_cref(iter)->type) {
  48. case Item_Group:
  49. type = ActionMenuItemTypeGroup;
  50. break;
  51. case Item_Playlist:
  52. type = ActionMenuItemTypePlaylist;
  53. break;
  54. case Item_SubGhz:
  55. type = ActionMenuItemTypeSubGHz;
  56. break;
  57. case Item_RFID:
  58. type = ActionMenuItemTypeRFID;
  59. break;
  60. case Item_IR:
  61. type = ActionMenuItemTypeIR;
  62. break;
  63. default:
  64. type = ActionMenuItemTypeGroup; // TODO: Does this ever get hit?
  65. }
  66. action_menu_add_item(menu, label, index, scene_items_item_callback, type, app);
  67. }
  68. } else {
  69. FURI_LOG_W(TAG, "No items for: %s", furi_string_get_cstr(items_view->path));
  70. // TODO: Display Error popup? Empty folder?
  71. }
  72. // Always add the "Settings" item at the end of our list - but only at top level!
  73. if(app->depth == 0) {
  74. action_menu_add_item(
  75. menu,
  76. "Settings",
  77. item_view_size, // last item!
  78. scene_items_item_callback,
  79. ActionMenuItemTypeSettings,
  80. app);
  81. }
  82. view_dispatcher_switch_to_view(app->view_dispatcher, Q_ActionMenu);
  83. }
  84. bool scene_items_on_event(void* context, SceneManagerEvent event) {
  85. App* app = context;
  86. bool consumed = false;
  87. FURI_LOG_I(TAG, "device on_event");
  88. switch(event.type) {
  89. case SceneManagerEventTypeCustom:
  90. if(event.event == Event_ButtonPressed) {
  91. consumed = true;
  92. furi_delay_ms(100);
  93. FURI_LOG_I(TAG, "button pressed is %d", app->selected_item);
  94. if(app->selected_item < (int)ItemArray_size(app->items_view->items)) {
  95. Item* item = ItemArray_get(app->items_view->items, app->selected_item);
  96. if(item->type == Item_Group) {
  97. app->depth++;
  98. ItemsView* new_items = item_get_items_view_from_path(app, item->path);
  99. item_items_view_free(app->items_view);
  100. app->items_view = new_items;
  101. scene_manager_next_scene(app->scene_manager, Q_Scene_Items);
  102. } else {
  103. FURI_LOG_I(
  104. TAG, "Initiating item action: %s", furi_string_get_cstr(item->name));
  105. // LED goes blinky blinky
  106. App* app = context;
  107. notification_message(app->notifications, &sequence_blink_start_blue);
  108. // Prepare error string for action calls
  109. FuriString* error;
  110. error = furi_string_alloc();
  111. action_tx(app, item, error);
  112. if(furi_string_size(error)) {
  113. FURI_LOG_E(TAG, furi_string_get_cstr(error));
  114. // Change LED to Red and Vibrate!
  115. notification_message(app->notifications, &sequence_error);
  116. // Display DialogEx popup or something?
  117. }
  118. furi_string_free(error);
  119. // Turn off LED light
  120. notification_message(app->notifications, &sequence_blink_stop);
  121. }
  122. } else {
  123. FURI_LOG_I(TAG, "Selected Settings!");
  124. // TODO: Do we need to free this current items_view??
  125. scene_manager_next_scene(app->scene_manager, Q_Scene_Settings);
  126. }
  127. }
  128. break;
  129. case SceneManagerEventTypeBack:
  130. FURI_LOG_I(TAG, "Back button pressed!");
  131. consumed = false; // Ensure Back event continues to propagate
  132. if(app->depth >= 0) {
  133. // take our current ItemsView path, and go back up a level
  134. FuriString* parent_path;
  135. parent_path = furi_string_alloc();
  136. path_extract_dirname(furi_string_get_cstr(app->items_view->path), parent_path);
  137. app->depth--;
  138. ItemsView* new_items = item_get_items_view_from_path(app, parent_path);
  139. item_items_view_free(app->items_view);
  140. app->items_view = new_items;
  141. furi_string_free(parent_path);
  142. } else {
  143. FURI_LOG_W(TAG, "At the root level!");
  144. }
  145. break;
  146. default:
  147. FURI_LOG_I(TAG, "Custom event not handled");
  148. break;
  149. }
  150. FURI_LOG_I(TAG, "Generic event not handled");
  151. return consumed;
  152. }
  153. void scene_items_on_exit(void* context) {
  154. App* app = context;
  155. ActionMenu* menu = app->action_menu;
  156. action_menu_reset(menu);
  157. FURI_LOG_I(TAG, "on_exit. depth = %d", app->depth);
  158. }