Skip to content

Commit cb51d40

Browse files
committed
Based on file list widget changes in Next-Flip#344
1 parent f5592ca commit cb51d40

8 files changed

Lines changed: 165 additions & 33 deletions

File tree

applications/main/archive/scenes/archive_scene_delete.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ void archive_scene_delete_on_enter(void* context) {
3535
"\e#Delete %d files?\e#",
3636
model->selected_count);
3737
widget_add_file_list_element(
38-
app->widget, 0, 23, 3, model->selected_files, model->selected_count);
38+
app->widget,
39+
0,
40+
23,
41+
3,
42+
model->selected_files,
43+
model->selected_count,
44+
14,
45+
FRAME_HEIGHT * 3,
46+
false);
3947
} else {
4048
ArchiveFile_t* current = archive_get_current_file(browser);
4149
FuriString* filename = furi_string_alloc();

applications/services/gui/modules/widget.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55

66
ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST); // NOLINT
77

8-
struct Widget {
9-
View* view;
10-
void* context;
11-
};
12-
138
typedef struct {
149
ElementArray_t element;
1510
} GuiWidgetModel;
@@ -125,10 +120,13 @@ WidgetElement* widget_add_file_list_element(
125120
uint8_t y,
126121
uint8_t lines,
127122
FuriString** files,
128-
size_t count) {
123+
size_t count,
124+
uint8_t scrollbar_y,
125+
uint8_t scrollbar_height,
126+
bool show_size) {
129127
furi_assert(widget);
130-
WidgetElement* file_list_element =
131-
widget_element_file_list_create(widget, x, y, lines, files, count);
128+
WidgetElement* file_list_element = widget_element_file_list_create(
129+
widget, x, y, lines, files, count, scrollbar_y, scrollbar_height, show_size);
132130
widget_add_element(widget, file_list_element);
133131
return file_list_element;
134132
}

applications/services/gui/modules/widget.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,26 @@ View* widget_get_view(Widget* widget);
4343

4444
/** Add File List Element
4545
*
46-
* @param widget Widget instance
47-
* @param x x coordinate
48-
* @param y y coordinate
49-
* @param lines Number of lines visible
50-
* @param files Array of FuriString pointers
51-
* @param count Number of files
46+
* @param widget Widget instance
47+
* @param x x coordinate
48+
* @param y y coordinate
49+
* @param lines Number of lines visible
50+
* @param files Array of FuriString pointers
51+
* @param count Number of files
52+
* @param scrollbar_y Y coordinate of the scrollbar
53+
* @param scrollbar_height Height of the scrollbar
54+
* @param show_size Show file size
5255
*/
5356
WidgetElement* widget_add_file_list_element(
5457
Widget* widget,
5558
uint8_t x,
5659
uint8_t y,
5760
uint8_t lines,
5861
FuriString** files,
59-
size_t count);
62+
size_t count,
63+
uint8_t scrollbar_y,
64+
uint8_t scrollbar_height,
65+
bool show_size);
6066

6167
/** Add Multi String Element
6268
*

applications/services/gui/modules/widget_elements/widget_element.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#pragma once
77

8+
#include "input/input.h"
9+
810
#ifdef __cplusplus
911
extern "C" {
1012
#endif

applications/services/gui/modules/widget_elements/widget_element_file_list.c

Lines changed: 119 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@
66
#include "archive/archive_i.h"
77
#include "assets_icons.h"
88

9+
#define SCROLL_INTERVAL (333)
10+
#define SCROLL_DELAY (2)
11+
12+
const char* units_short[] = {"B", "K", "M", "G", "T"};
13+
914
typedef struct {
10-
FuriString* name;
15+
FuriString* path;
1116
const Icon* icon;
17+
char size_num[8];
18+
char size_unit[2];
1219
} FileListItem;
1320

1421
typedef struct {
@@ -18,8 +25,35 @@ typedef struct {
1825
FileListItem* files;
1926
size_t count;
2027
size_t offset;
28+
uint8_t scrollbar_y;
29+
bool show_size;
30+
uint8_t scrollbar_height;
31+
size_t scroll_counter;
32+
FuriTimer* scroll_timer;
2133
} FileListModel;
2234

35+
static void format_file_size(
36+
uint64_t size,
37+
char* num_buf,
38+
size_t num_size,
39+
char* unit_buf,
40+
size_t unit_size) {
41+
double formatted_size = size;
42+
uint8_t unit = 0;
43+
44+
while(formatted_size >= 1024 && unit < COUNT_OF(units_short) - 1) {
45+
formatted_size /= 1024;
46+
unit++;
47+
}
48+
49+
if(unit == 0) {
50+
snprintf(num_buf, num_size, "%d", (int)formatted_size);
51+
} else {
52+
snprintf(num_buf, num_size, "%.1f", (double)formatted_size);
53+
}
54+
snprintf(unit_buf, unit_size, "%s", units_short[unit]);
55+
}
56+
2357
static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element) {
2458
furi_assert(canvas);
2559
furi_assert(element);
@@ -32,22 +66,53 @@ static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element
3266
if(idx < model->count) {
3367
canvas_draw_icon(
3468
canvas, model->x + 2, model->y + (i * FRAME_HEIGHT) - 9, model->files[idx].icon);
35-
canvas_draw_str(
69+
70+
size_t inner_x = 123;
71+
if(model->show_size && model->files[idx].size_num[0] != '\0') {
72+
canvas_set_font(canvas, FontPrimary);
73+
uint16_t num_width = canvas_string_width(canvas, model->files[idx].size_num);
74+
canvas_set_font(canvas, FontSecondary);
75+
uint16_t unit_width = canvas_string_width(canvas, model->files[idx].size_unit);
76+
uint16_t total_width = num_width + unit_width;
77+
inner_x = model->x + (128 - model->x) - total_width - 5;
78+
inner_x--;
79+
80+
canvas_set_font(canvas, FontPrimary);
81+
canvas_draw_str(
82+
canvas, inner_x, model->y + (i * FRAME_HEIGHT), model->files[idx].size_num);
83+
canvas_set_font(canvas, FontSecondary);
84+
canvas_draw_str(
85+
canvas,
86+
inner_x + num_width + 1,
87+
model->y + (i * FRAME_HEIGHT),
88+
model->files[idx].size_unit);
89+
}
90+
91+
size_t scroll_counter = model->scroll_counter;
92+
scroll_counter =
93+
i == 0 ? (model->count > model->lines &&
94+
(scroll_counter < SCROLL_DELAY ? 0 : scroll_counter - SCROLL_DELAY)) :
95+
0;
96+
97+
elements_scrollable_text_line(
3698
canvas,
3799
model->x + 15,
38100
model->y + (i * FRAME_HEIGHT),
39-
furi_string_get_cstr(model->files[idx].name));
101+
inner_x - 19,
102+
model->files[idx].path,
103+
scroll_counter,
104+
i != 0 || model->count <= model->lines);
40105
}
41106
}
42107

43108
if(model->count > model->lines) {
44109
elements_scrollbar_pos(
45110
canvas,
46111
128,
47-
model->y - 9,
48-
model->lines * FRAME_HEIGHT,
112+
model->scrollbar_y,
113+
model->scrollbar_height,
49114
model->offset,
50-
model->count - 2);
115+
model->count - (model->lines - 1));
51116
}
52117
}
53118

@@ -56,24 +121,37 @@ static bool widget_element_file_list_input(InputEvent* event, WidgetElement* ele
56121
FileListModel* model = element->model;
57122
bool consumed = false;
58123

59-
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
124+
if(model->count > model->lines &&
125+
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
60126
if(event->key == InputKeyUp) {
61-
model->offset = (model->offset > 0) ? model->offset - 1 : model->count - 3;
127+
model->offset = (model->offset > 0) ? model->offset - 1 : model->count - model->lines;
128+
model->scroll_counter = 0;
62129
consumed = true;
63130
} else if(event->key == InputKeyDown) {
64-
model->offset = ((model->offset + 3) < model->count) ? model->offset + 1 : 0;
131+
model->offset = ((model->offset + model->lines) < model->count) ? model->offset + 1 :
132+
0;
133+
model->scroll_counter = 0;
65134
consumed = true;
66135
}
67136
}
68137

69138
return consumed;
70139
}
71140

141+
static void widget_element_file_list_timer_callback(void* context) {
142+
WidgetElement* element = context;
143+
FileListModel* file_model = element->model;
144+
file_model->scroll_counter++;
145+
with_view_model(element->parent->view, void* _model, { UNUSED(_model); }, true);
146+
}
147+
72148
static void widget_element_file_list_free(WidgetElement* element) {
73149
furi_assert(element);
74150
FileListModel* model = element->model;
151+
furi_timer_stop(model->scroll_timer);
152+
furi_timer_free(model->scroll_timer);
75153
for(size_t i = 0; i < model->count; i++) {
76-
furi_string_free(model->files[i].name);
154+
furi_string_free(model->files[i].path);
77155
}
78156
free(model->files);
79157
free(model);
@@ -86,26 +164,48 @@ WidgetElement* widget_element_file_list_create(
86164
uint8_t y,
87165
uint8_t lines,
88166
FuriString** files,
89-
size_t count) {
167+
size_t count,
168+
uint8_t scrollbar_y,
169+
uint8_t scrollbar_height,
170+
bool show_size) {
90171
// Allocate and init model
91172
FileListModel* model = malloc(sizeof(FileListModel));
92173
model->x = x;
93174
model->y = y;
94175
model->lines = lines;
95176
model->count = count;
177+
model->scrollbar_y = scrollbar_y;
178+
model->scrollbar_height = scrollbar_height;
179+
model->show_size = show_size;
96180
model->offset = 0;
181+
model->scroll_counter = 0;
97182
model->files = malloc(sizeof(FileListItem) * count);
183+
98184
Storage* storage = furi_record_open(RECORD_STORAGE);
185+
FileInfo info;
99186
for(size_t i = 0; i < count; i++) {
100-
model->files[i].name = furi_string_alloc();
101-
path_extract_filename(files[i], model->files[i].name, false);
187+
model->files[i].path = furi_string_alloc();
188+
path_extract_filename(files[i], model->files[i].path, false);
189+
model->files[i].size_num[0] = '\0';
190+
model->files[i].size_unit[0] = '\0';
191+
102192
if(storage_dir_exists(storage, furi_string_get_cstr(files[i]))) {
103193
model->files[i].icon = &I_dir_10px;
104194
} else {
105-
const char* ext = strrchr(furi_string_get_cstr(model->files[i].name), '.');
195+
const char* ext = strrchr(furi_string_get_cstr(model->files[i].path), '.');
106196
model->files[i].icon = (ext && strcasecmp(ext, ".js") == 0) ? &I_js_script_10px :
107197
&I_unknown_10px;
108198
}
199+
200+
if(show_size) {
201+
storage_common_stat(storage, furi_string_get_cstr(files[i]), &info);
202+
format_file_size(
203+
info.size,
204+
model->files[i].size_num,
205+
sizeof(model->files[i].size_num),
206+
model->files[i].size_unit,
207+
sizeof(model->files[i].size_unit));
208+
}
109209
}
110210
furi_record_close(RECORD_STORAGE);
111211

@@ -116,5 +216,10 @@ WidgetElement* widget_element_file_list_create(
116216
element->free = widget_element_file_list_free;
117217
element->parent = widget;
118218
element->model = model;
219+
220+
model->scroll_timer =
221+
furi_timer_alloc(widget_element_file_list_timer_callback, FuriTimerTypePeriodic, element);
222+
furi_timer_start(model->scroll_timer, SCROLL_INTERVAL);
223+
119224
return element;
120225
}

applications/services/gui/modules/widget_elements/widget_element_i.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#pragma once
77

8-
#include "../widget.h"
8+
#include "../widget_i.h"
99
#include "widget_element.h"
1010
#include <furi.h>
1111
#include <gui/view.h>
@@ -41,7 +41,10 @@ WidgetElement* widget_element_file_list_create(
4141
uint8_t y,
4242
uint8_t lines,
4343
FuriString** files,
44-
size_t count);
44+
size_t count,
45+
uint8_t scrollbar_y,
46+
uint8_t scrollbar_height,
47+
bool show_size);
4548

4649
/** Create multi string element */
4750
WidgetElement* widget_element_string_multiline_create(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include "widget.h"
4+
#include <furi.h>
5+
#include <m-array.h>
6+
7+
struct Widget {
8+
View* view;
9+
void* context;
10+
};

targets/f7/api_symbols.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3836,7 +3836,7 @@ Function,-,vsscanf,int,"const char*, const char*, __gnuc_va_list"
38363836
Function,-,wcstombs,size_t,"char*, const wchar_t*, size_t"
38373837
Function,-,wctomb,int,"char*, wchar_t"
38383838
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"
3839+
Function,+,widget_add_file_list_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, FuriString**, size_t, uint8_t, uint8_t, _Bool"
38403840
Function,+,widget_add_frame_element,WidgetElement*,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
38413841
Function,+,widget_add_icon_element,WidgetElement*,"Widget*, uint8_t, uint8_t, const Icon*"
38423842
Function,+,widget_add_string_element,WidgetElement*,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*"

0 commit comments

Comments
 (0)