Added file list widget to delete screen

- New file list widget was created to show the to-be-deleted files on the delete screen, rather than just "Delete n files?" It's also scrollable.
- 'Select' action menu option was removed from the favorites tab since favorites already have a mechanism for that stuff.
This commit is contained in:
Alexander Bays
2024-12-21 19:41:49 -06:00
parent 12de1570be
commit 4afb86bfbd
10 changed files with 188 additions and 19 deletions
@@ -733,3 +733,18 @@ void archive_clear_selection(ArchiveBrowserViewModel* model) {
file->selected = false;
}
}
void archive_deselect_children(ArchiveBrowserViewModel* model, const char* parent) {
size_t write_idx = 0;
for(size_t i = 0; i < model->selected_count; i++) {
if(!furi_string_start_with(model->selected_files[i], parent)) {
if(write_idx != i) {
model->selected_files[write_idx] = model->selected_files[i];
}
write_idx++;
} else {
furi_string_free(model->selected_files[i]);
}
}
model->selected_count = write_idx;
}
@@ -112,3 +112,4 @@ void archive_leave_dir(ArchiveBrowserView* browser);
void archive_refresh_dir(ArchiveBrowserView* browser);
void archive_clear_selection(ArchiveBrowserViewModel* model);
void archive_deselect_children(ArchiveBrowserViewModel* model, const char* parent);
@@ -307,20 +307,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
if(!current->selected) {
// If current file type is a folder, deselect all files that start with the same path to not have a conflict.
if(current->type == ArchiveFileTypeFolder) {
size_t write_idx = 0;
for(size_t i = 0; i < model->selected_count; i++) {
if(!furi_string_start_with(
model->selected_files[i], current->path)) {
if(write_idx != i) {
model->selected_files[write_idx] =
model->selected_files[i];
}
write_idx++;
} else {
furi_string_free(model->selected_files[i]);
}
}
model->selected_count = write_idx;
archive_deselect_children(model, furi_string_get_cstr(current->path));
}
model->selected_files[model->selected_count] =
furi_string_alloc_set(current->path);
@@ -28,12 +28,14 @@ void archive_scene_delete_on_enter(void* context) {
browser->view,
ArchiveBrowserViewModel * model,
{
if(model->select_mode && model->selected_count > 0) {
if(model->select_mode && model->selected_count > 1) {
snprintf(
delete_str,
sizeof(delete_str),
"\e#Delete %d files?\e#",
model->selected_count);
widget_add_file_list_element(
app->widget, 0, 23, 3, model->selected_files, model->selected_count);
} else {
ArchiveFile_t* current = archive_get_current_file(browser);
FuriString* filename = furi_string_alloc();
@@ -125,10 +125,12 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
menu_array_push_raw(model->context_menu),
"Info",
ArchiveBrowserEventFileMenuInfo);
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
model->select_mode ? "Deselect" : "Select",
ArchiveBrowserEventFileMenuSelectMode);
if(!favorites) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
model->select_mode ? "Deselect" : "Select",
ArchiveBrowserEventFileMenuSelectMode);
}
if(selected->type != ArchiveFileTypeFolder) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
@@ -119,6 +119,20 @@ static void widget_add_element(Widget* widget, WidgetElement* element) {
true);
}
WidgetElement* widget_add_file_list_element(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count) {
furi_assert(widget);
WidgetElement* file_list_element =
widget_element_file_list_create(widget, x, y, lines, files, count);
widget_add_element(widget, file_list_element);
return file_list_element;
}
WidgetElement* widget_add_string_multiline_element(
Widget* widget,
uint8_t x,
@@ -41,6 +41,23 @@ void widget_reset(Widget* widget);
*/
View* widget_get_view(Widget* widget);
/** Add File List Element
*
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param lines Number of lines visible
* @param files Array of FuriString pointers
* @param count Number of files
*/
WidgetElement* widget_add_file_list_element(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count);
/** Add Multi String Element
*
* @param widget Widget instance
@@ -0,0 +1,121 @@
#include "assets_icons.h"
#include "path.h"
#include "widget_element_i.h"
#include <gui/elements.h>
#include <core/common_defines.h>
#include "archive/archive_i.h"
typedef struct {
FuriString* name;
bool is_dir;
} FileListItem;
typedef struct {
uint8_t x;
uint8_t y;
uint8_t lines;
FileListItem* files;
size_t count;
size_t offset;
} FileListModel;
static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element) {
furi_assert(canvas);
furi_assert(element);
FileListModel* model = element->model;
size_t items_visible = MIN(model->lines, model->count);
canvas_set_font(canvas, FontSecondary);
for(size_t i = 0; i < items_visible; i++) {
size_t idx = model->offset + i;
if(idx < model->count) {
canvas_draw_icon(
canvas,
model->x + 2,
model->y + (i * FRAME_HEIGHT) - 9,
model->files[idx].is_dir ? &I_dir_10px : &I_unknown_10px);
canvas_draw_str(
canvas,
model->x + 15,
model->y + (i * FRAME_HEIGHT),
furi_string_get_cstr(model->files[idx].name));
}
}
if(model->count > model->lines) {
elements_scrollbar_pos(
canvas,
128,
model->y - 9,
model->lines * FRAME_HEIGHT,
model->offset,
model->count - 2);
}
}
static bool widget_element_file_list_input(InputEvent* event, WidgetElement* element) {
furi_assert(element);
FileListModel* model = element->model;
bool consumed = false;
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
if(event->key == InputKeyUp) {
model->offset = (model->offset > 0) ? model->offset - 1 : model->count - 3;
consumed = true;
} else if(event->key == InputKeyDown) {
model->offset = ((model->offset + 3) < model->count) ? model->offset + 1 : 0;
consumed = true;
}
}
return consumed;
}
static void widget_element_file_list_free(WidgetElement* element) {
furi_assert(element);
FileListModel* model = element->model;
for(size_t i = 0; i < model->count; i++) {
furi_string_free(model->files[i].name);
}
free(model->files);
free(model);
free(element);
}
WidgetElement* widget_element_file_list_create(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count) {
// Allocate and init model
FileListModel* model = malloc(sizeof(FileListModel));
model->x = x;
model->y = y;
model->lines = lines;
model->count = count;
model->offset = 0;
model->files = malloc(sizeof(FileListItem) * count);
Storage* storage = furi_record_open(RECORD_STORAGE);
for(size_t i = 0; i < count; i++) {
FileInfo fileinfo;
model->files[i].name = furi_string_alloc();
path_extract_filename(files[i], model->files[i].name, false);
model->files[i].is_dir = false;
if(storage_common_stat(storage, furi_string_get_cstr(files[i]), &fileinfo) == FSE_OK) {
model->files[i].is_dir = file_info_is_dir(&fileinfo);
}
}
furi_record_close(RECORD_STORAGE);
// Allocate and init Element
WidgetElement* element = malloc(sizeof(WidgetElement));
element->draw = widget_element_file_list_draw;
element->input = widget_element_file_list_input;
element->free = widget_element_file_list_free;
element->parent = widget;
element->model = model;
return element;
}
@@ -34,6 +34,15 @@ struct WidgetElement {
Widget* parent;
};
/** Create file list element */
WidgetElement* widget_element_file_list_create(
Widget* widget,
uint8_t x,
uint8_t y,
uint8_t lines,
FuriString** files,
size_t count);
/** Create multi string element */
WidgetElement* widget_element_string_multiline_create(
uint8_t x,
+1
View File
@@ -3836,6 +3836,7 @@ Function,-,vsscanf,int,"const char*, const char*, __gnuc_va_list"
Function,-,wcstombs,size_t,"char*, const wchar_t*, size_t"
Function,-,wctomb,int,"char*, wchar_t"
Function,+,widget_add_button_element,WidgetElement*,"Widget*, GuiButtonType, const char*, ButtonCallback, void*"
Function,+,widget_add_file_list_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, FuriString**, size_t"
Function,+,widget_add_frame_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,widget_add_icon_element,WidgetElement*,"Widget*, uint8_t, uint8_t, const Icon*"
Function,+,widget_add_string_element,WidgetElement*,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*"
1 entry status name type params
3836 Function - wcstombs size_t char*, const wchar_t*, size_t
3837 Function - wctomb int char*, wchar_t
3838 Function + widget_add_button_element WidgetElement* Widget*, GuiButtonType, const char*, ButtonCallback, void*
3839 Function + widget_add_file_list_element WidgetElement* Widget*, uint8_t, uint8_t, uint8_t, FuriString**, size_t
3840 Function + widget_add_frame_element WidgetElement* Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t
3841 Function + widget_add_icon_element WidgetElement* Widget*, uint8_t, uint8_t, const Icon*
3842 Function + widget_add_string_element WidgetElement* Widget*, uint8_t, uint8_t, Align, Align, Font, const char*