Archive: New tab for searching files

This commit is contained in:
Willy-JL
2023-07-03 22:31:54 +02:00
parent 5520fd3d66
commit 761ea80454
14 changed files with 187 additions and 7 deletions
+13
View File
@@ -51,6 +51,11 @@ static ArchiveApp* archive_alloc() {
view_dispatcher, ArchiveViewStack, view_stack_get_view(archive->view_stack));
archive->browser = browser_alloc();
with_view_model(
archive->browser->view,
ArchiveBrowserViewModel * model,
{ model->archive = archive; },
true);
view_dispatcher_add_view(
archive->view_dispatcher, ArchiveViewBrowser, archive_browser_get_view(archive->browser));
@@ -64,6 +69,14 @@ void archive_free(ArchiveApp* archive) {
furi_assert(archive);
ViewDispatcher* view_dispatcher = archive->view_dispatcher;
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneInfo, false);
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneSearch, false);
if(archive->thread) {
furi_thread_join(archive->thread);
furi_thread_free(archive->thread);
archive->thread = NULL;
}
// Loading
loading_free(archive->loading);
@@ -5,6 +5,7 @@
static const char* known_apps[] = {
[ArchiveAppTypeU2f] = "u2f",
[ArchiveAppTypeSearch] = "search",
};
ArchiveAppTypeEnum archive_get_app_type(const char* path) {
@@ -35,6 +36,9 @@ bool archive_app_is_available(void* context, const char* path) {
res = storage_file_exists(storage, U2F_KEY_FILE) &&
storage_file_exists(storage, U2F_CNT_FILE);
break;
case ArchiveAppTypeSearch:
res = true;
break;
default:
break;
}
@@ -48,15 +52,17 @@ bool archive_app_read_dir(void* context, const char* path) {
furi_assert(path);
ArchiveBrowserView* browser = context;
archive_file_array_rm_all(browser);
ArchiveAppTypeEnum app = archive_get_app_type(path);
switch(app) {
case ArchiveAppTypeU2f:
archive_add_app_item(browser, "/app:u2f/U2F Token");
archive_file_array_rm_all(browser);
return true;
case ArchiveAppTypeSearch:
return true;
default:
archive_file_array_rm_all(browser);
return false;
}
}
@@ -78,6 +84,8 @@ void archive_app_delete_file(void* context, const char* path) {
archive_favorites_delete("/app:u2f/U2F Token");
}
break;
case ArchiveAppTypeSearch:
break;
default:
break;
}
@@ -2,12 +2,14 @@
typedef enum {
ArchiveAppTypeU2f,
ArchiveAppTypeSearch,
ArchiveAppTypeUnknown,
ArchiveAppsTotal,
} ArchiveAppTypeEnum;
static const ArchiveFileTypeEnum app_file_types[] = {
[ArchiveAppTypeU2f] = ArchiveFileTypeU2f,
[ArchiveAppTypeSearch] = ArchiveFileTypeSearch,
[ArchiveAppTypeUnknown] = ArchiveFileTypeUnknown,
};
@@ -489,6 +489,18 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
furi_assert(browser);
ArchiveTabEnum tab = archive_get_tab(browser);
if(tab == ArchiveTabSearch) {
ArchiveApp* archive;
with_view_model(
browser->view, ArchiveBrowserViewModel * model, { archive = model->archive; }, false);
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneSearch, false);
if(archive->thread) {
furi_thread_join(archive->thread);
furi_thread_free(archive->thread);
archive->thread = NULL;
}
}
browser->last_tab_switch_dir = key;
for(int i = 0; i < 2; i++) {
@@ -516,6 +528,11 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
if(app_name != NULL) {
if(archive_app_is_available(browser, furi_string_get_cstr(browser->path))) {
tab_empty = false;
if(tab == ArchiveTabSearch) {
archive_file_array_rm_all(browser);
archive_add_app_item(browser, "/app:search/Search for files");
archive_set_item_count(browser, 1);
}
}
}
} else {
@@ -17,6 +17,7 @@ static const char* tab_default_paths[] = {
[ArchiveTabBadKb] = EXT_PATH("badkb"),
[ArchiveTabU2f] = "/app:u2f",
[ArchiveTabApplications] = EXT_PATH("apps"),
[ArchiveTabSearch] = "/app:search",
[ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX,
[ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX,
};
@@ -33,6 +34,7 @@ static const char* known_ext[] = {
[ArchiveFileTypeBadKb] = ".txt",
[ArchiveFileTypeU2f] = "?",
[ArchiveFileTypeApplication] = ".fap",
[ArchiveFileTypeSearch] = "*",
[ArchiveFileTypeUpdateManifest] = ".fuf",
[ArchiveFileTypeFolder] = "?",
[ArchiveFileTypeUnknown] = "*",
@@ -48,6 +50,7 @@ static const ArchiveFileTypeEnum known_type[] = {
[ArchiveTabBadKb] = ArchiveFileTypeBadKb,
[ArchiveTabU2f] = ArchiveFileTypeU2f,
[ArchiveTabApplications] = ArchiveFileTypeApplication,
[ArchiveTabSearch] = ArchiveFileTypeSearch,
[ArchiveTabInternal] = ArchiveFileTypeUnknown,
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
};
@@ -21,6 +21,7 @@ typedef enum {
ArchiveFileTypeBadKb,
ArchiveFileTypeU2f,
ArchiveFileTypeApplication,
ArchiveFileTypeSearch,
ArchiveFileTypeUpdateManifest,
ArchiveFileTypeFolder,
ArchiveFileTypeUnknown,
@@ -301,6 +301,19 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
archive_enter_dir(browser, selected->path);
consumed = true;
break;
case ArchiveBrowserEventSearch: {
bool open =
!scene_manager_get_scene_state(archive->scene_manager, ArchiveAppSceneSearch);
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneSearch, false);
if(archive->thread) {
furi_thread_join(archive->thread);
furi_thread_free(archive->thread);
archive->thread = NULL;
}
if(open) scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneSearch);
consumed = true;
break;
}
case ArchiveBrowserEventFavMoveUp:
archive_file_array_swap(browser, 1);
consumed = true;
@@ -2,5 +2,6 @@ ADD_SCENE(archive, browser, Browser)
ADD_SCENE(archive, new_dir, NewDir)
ADD_SCENE(archive, rename, Rename)
ADD_SCENE(archive, delete, Delete)
ADD_SCENE(archive, search, Search)
ADD_SCENE(archive, info, Info)
ADD_SCENE(archive, show, Show)
@@ -134,7 +134,7 @@ void archive_scene_info_on_enter(void* context) {
if(is_dir) {
scene_manager_set_scene_state(instance->scene_manager, ArchiveAppSceneInfo, true);
instance->thread = furi_thread_alloc_ex(
"ArchiveDirWalk", 1024, (FuriThreadCallback)archive_scene_info_dirwalk, instance);
"ArchiveInfoDirWalk", 1024, (FuriThreadCallback)archive_scene_info_dirwalk, instance);
furi_thread_start(instance->thread);
}
}
@@ -0,0 +1,105 @@
#include "../archive_i.h"
#include "../helpers/archive_favorites.h"
#include "../helpers/archive_files.h"
#include "../helpers/archive_browser.h"
#include "archive/views/archive_browser_view.h"
#include "toolbox/path.h"
#include <dialogs/dialogs.h>
#define TAG "Archive"
#define SCENE_SEARCH_CUSTOM_EVENT (0UL)
void archive_scene_search_text_input_callback(void* context) {
ArchiveApp* archive = (ArchiveApp*)context;
view_dispatcher_send_custom_event(archive->view_dispatcher, SCENE_SEARCH_CUSTOM_EVENT);
}
void archive_scene_search_on_enter(void* context) {
ArchiveApp* archive = context;
TextInput* text_input = archive->text_input;
strlcpy(archive->text_store, "", MAX_NAME_LEN);
text_input_set_header_text(text_input, "Search for files:");
text_input_set_result_callback(
text_input,
archive_scene_search_text_input_callback,
context,
archive->text_store,
MAX_NAME_LEN,
false);
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
}
uint32_t archive_scene_search_dirwalk(void* context) {
furi_assert(context);
ArchiveApp* archive = context;
uint32_t count = 1;
DirWalk* dir_walk = dir_walk_alloc(furi_record_open(RECORD_STORAGE));
FuriString* path = furi_string_alloc();
FileInfo fileinfo;
if(dir_walk_open(dir_walk, STORAGE_EXT_PATH_PREFIX)) {
while(scene_manager_get_scene_state(archive->scene_manager, ArchiveAppSceneSearch)) {
DirWalkResult result = dir_walk_read(dir_walk, path, &fileinfo);
if(result == DirWalkError) {
archive_add_app_item(archive->browser, "/app:search/Error while searching!");
archive_set_item_count(archive->browser, ++count);
break;
}
if(result == DirWalkLast) {
break;
}
if(!file_info_is_dir(&fileinfo) &&
furi_string_search_str(path, archive->text_store) != FURI_STRING_FAILURE) {
archive_add_file_item(archive->browser, false, furi_string_get_cstr(path));
archive_set_item_count(archive->browser, ++count);
}
}
} else {
archive_add_app_item(archive->browser, "/app:search/Error while searching!");
archive_set_item_count(archive->browser, ++count);
}
furi_string_set(
archive_get_file_at(archive->browser, 0)->path, "/app:search/Search for files");
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneSearch, false);
furi_string_free(path);
dir_walk_free(dir_walk);
return 0;
}
bool archive_scene_search_on_event(void* context, SceneManagerEvent event) {
ArchiveApp* archive = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_SEARCH_CUSTOM_EVENT) {
archive_file_array_rm_all(archive->browser);
archive_add_app_item(archive->browser, "/app:search/Cancel search");
archive_set_item_count(archive->browser, 1);
// Thread here is fine because only the info pane uses it too,
// but only for directories, which are ignored for search
scene_manager_set_scene_state(archive->scene_manager, ArchiveAppSceneSearch, true);
archive->thread = furi_thread_alloc_ex(
"ArchiveSearchDirWalk",
1024,
(FuriThreadCallback)archive_scene_search_dirwalk,
archive);
furi_thread_start(archive->thread);
scene_manager_previous_scene(archive->scene_manager);
consumed = true;
}
}
return consumed;
}
void archive_scene_search_on_exit(void* context) {
ArchiveApp* archive = context;
text_input_reset(archive->text_input);
}
@@ -19,6 +19,7 @@ static const char* ArchiveTabNames[] = {
[ArchiveTabBadKb] = "Bad KB",
[ArchiveTabU2f] = "U2F",
[ArchiveTabApplications] = "Apps",
[ArchiveTabSearch] = "Search",
[ArchiveTabInternal] = "Internal",
[ArchiveTabBrowser] = "Browser",
};
@@ -35,6 +36,7 @@ static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeBadKb] = &I_badkb_10px,
[ArchiveFileTypeU2f] = &I_u2f_10px,
[ArchiveFileTypeApplication] = &I_Apps_10px,
[ArchiveFileTypeSearch] = &I_search_10px,
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
[ArchiveFileTypeFolder] = &I_dir_10px,
[ArchiveFileTypeUnknown] = &I_unknown_10px,
@@ -197,7 +199,8 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
ArchiveFile_t* file = files_array_get(
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
file_type = file->type;
bool ext = model->tab_idx == ArchiveTabBrowser || model->tab_idx == ArchiveTabInternal;
bool ext = strncmp(archive_get_default_path(model->tab_idx), "/app:", 5) == 0 ||
model->tab_idx == ArchiveTabBrowser || model->tab_idx == ArchiveTabInternal;
if(file_type == ArchiveFileTypeApplication) {
if(file->custom_icon_data) {
custom_icon_data = file->custom_icon_data;
@@ -261,6 +264,10 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m
furi_assert(model);
const char* tab_name = ArchiveTabNames[model->tab_idx];
if(model->tab_idx == ArchiveTabSearch &&
scene_manager_get_scene_state(model->archive->scene_manager, ArchiveAppSceneSearch)) {
tab_name = "Searching";
}
bool clip = model->clipboard != NULL;
canvas_draw_icon(canvas, 0, 0, &I_Background_128x11);
@@ -354,6 +361,7 @@ static bool archive_view_input(InputEvent* event, void* context) {
ArchiveBrowserView* browser = context;
bool in_menu;
int32_t cur_item_idx;
bool move_fav_mode;
bool is_loading;
with_view_model(
@@ -361,6 +369,7 @@ static bool archive_view_input(InputEvent* event, void* context) {
ArchiveBrowserViewModel * model,
{
in_menu = model->menu;
cur_item_idx = model->item_idx;
move_fav_mode = model->move_fav;
is_loading = model->folder_loading || model->list_loading;
},
@@ -492,9 +501,12 @@ static bool archive_view_input(InputEvent* event, void* context) {
archive_update_offset(browser);
}
if(event->key == InputKeyOk) {
ArchiveFile_t* selected = archive_get_current_file(browser);
ArchiveFile_t* selected = archive_get_current_file(browser);
if(selected && selected->type == ArchiveFileTypeSearch) {
if(event->key == InputKeyOk && event->type == InputTypeShort && cur_item_idx == 0) {
browser->callback(ArchiveBrowserEventSearch, browser->context);
}
} else if(event->key == InputKeyOk) {
if(selected) {
bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
bool folder = selected->type == ArchiveFileTypeFolder;
@@ -30,6 +30,7 @@ typedef enum {
ArchiveTabBadKb,
ArchiveTabU2f,
ArchiveTabApplications,
ArchiveTabSearch,
ArchiveTabInternal,
ArchiveTabBrowser,
ArchiveTabTotal,
@@ -53,6 +54,8 @@ typedef enum {
ArchiveBrowserEventEnterDir,
ArchiveBrowserEventSearch,
ArchiveBrowserEventFavMoveUp,
ArchiveBrowserEventFavMoveDown,
ArchiveBrowserEventEnterFavMove,
@@ -90,6 +93,7 @@ struct ArchiveBrowserView {
};
typedef struct {
ArchiveApp* archive;
ArchiveTabEnum tab_idx;
files_array_t files;
Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

+1
View File
@@ -3466,6 +3466,7 @@ Variable,+,I_passport_DB,Icon,
Variable,+,I_passport_bad_46x49,Icon,
Variable,+,I_passport_happy_46x49,Icon,
Variable,+,I_passport_okay_46x49,Icon,
Variable,+,I_search_10px,Icon,
Variable,+,I_sub1_10px,Icon,
Variable,+,I_subplaylist_10px,Icon,
Variable,+,I_subrem_10px,Icon,
1 entry status name type params
3466 Variable + I_passport_bad_46x49 Icon
3467 Variable + I_passport_happy_46x49 Icon
3468 Variable + I_passport_okay_46x49 Icon
3469 Variable + I_search_10px Icon
3470 Variable + I_sub1_10px Icon
3471 Variable + I_subplaylist_10px Icon
3472 Variable + I_subrem_10px Icon